Golang数组与Slice,以及append函数的陷阱

Golang中数组的概念与C中相差无几。

1.声明一个数组

var array [5]int //声明一个数组。
var array2 [5]int 
array2=array //两个数组变量赋值,这个操作会导致一次数组的拷贝。
//比如
func test(){
	var array =[5]int{2,3,4,5,6}
	var array2 [5]int
	array2=array
	array[1]=9
	fmt.Printf("array:%v\n",array) //输出:array:[2 9 4 5 6]
	fmt.Printf("array2:%v\n",array2) //输出:array2:[2 3 4 5 6]
}

2.声明一个数组指针

var array *[5]int //声明一个数组指针。
var array2 *[5]int 
array2=array //两个数组指针赋值,不会拷贝底层数组,两个指针都指向同一个数组。
//比如
func test(){
	var array =&[5]int{2,3,4,5,6}
	var array2 *[5]int
	array2=array
	array[1]=9
	fmt.Printf("array:%v\n",array) // array:&[2 9 4 5 6]
	fmt.Printf("array2:%v\n",array2) //array2:&[2 9 4 5 6]
}

3.Slice

slice并不是单纯的一个指向数组的指针,它是一个结构体(包含:指针,长度,容量)

// 创建 nil 整型切片
var slice []int

上面创造了一个"nil切片",要注意到的就是golang中的nil也不是一个单纯的空指针,与Java中的null有着不同的意义。

Java中若是存在以下代码:

Object object=null;

这表示object这个变量不是任何内存的引用。

Golang中若是存在以下代码:

var slice []int=nil

表示slice被一个nil切片赋值,nil切片就是一个结构体中个变量都为"0值"。
即:nil切片{指针(NULL),长度(0),容量(0)}

4.Slice的赋值

如果讲一个Slice赋值个另外一个Slice了,那么他们是共享底层数组的
比如slice2=slice
那么,slice2中的指针与slice中的指针就指向了底层同一个数组。

还可以通过索引的方式来创建切片:

// 创建一个整型切片
// 其长度和容量都是 5 个元素
slice := []int{10, 20, 30, 40, 50}
// 创建一个新切片
// 其长度为 2 个元素,容量为 4 个元素
newSlice := slice[1:3]
/ 将第三个元素切片,并限制容量
// 其长度为 1 个元素,容量为 2 个元素
newSlice2 := slice[2:3:4]

Slice中长度代表了他能访问的区间,容量代表了append操作的区间。
如果append超过设定的区间,那么Slice底层就会扩容了

5.有陷阱的append操作

这部分是针对上面–>如果append超过设定的区间,那么Slice底层就会扩容了. 这句话做详细说明哈。

具体想说的都在下面的例子里:

func test(){
	var array =[]int{1,2,3,4,5}// len:5,capacity:5
	var newArray=array[1:3]// len:2,capacity:4   (已经使用了两个位置,所以还空两位置可以append)
	fmt.Printf("%p\n",array) //0xc420098000
	fmt.Printf("%p\n",newArray) //0xc420098008 可以看到newArray的地址指向的是array[1]的地址,即他们底层使用的还是一个数组
	fmt.Printf("%v\n",array) //[1 2 3 4 5]
	fmt.Printf("%v\n",newArray) //[2 3]

	newArray[1]=9 //更改后array、newArray都改变了
	fmt.Printf("%v\n",array) // [1 2 9 4 5]
	fmt.Printf("%v\n",newArray) // [2 9]

	newArray=append(newArray,11,12)//append 操作之后,array的len和capacity不变,newArray的len变为4,capacity:4。因为这是对newArray的操作
	fmt.Printf("%v\n",array) //[1 2 9 11 12] //注意对newArray做append操作之后,array[3],array[4]的值也发生了改变
	fmt.Printf("%v\n",newArray) //[2 9 11 12]

	newArray=append(newArray,13,14) // 因为newArray的len已经等于capacity,所以再次append就会超过capacity值,
	// 此时,append函数内部会创建一个新的底层数组(是一个扩容过的数组),并将array指向的底层数组拷贝过去,然后在追加新的值。
	fmt.Printf("%p\n",array) //0xc420098000
	fmt.Printf("%p\n",newArray) //0xc4200a0000
	fmt.Printf("%v\n",array) //[1 2 9 11 12]
	fmt.Printf("%v\n",newArray) //[2 9 11 12 13 14]  他两已经不再是指向同一个底层数组y了
}

所以知道我为啥说append有陷阱了吧?
append操作可能会导致原本使用同一个底层数组的两个Slice变量变为使用不同的底层数组。

关于这部分内容《go语言实战》里第四章讲的很清楚。

  • 8
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值