前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go之数组/切片

Go之数组/切片

作者头像
flytam
发布2020-01-14 18:01:21
5920
发布2020-01-14 18:01:21
举报

Go之数组/切片

初始化

Go中初始化一个数组如下
代码语言:javascript
复制
// 指定长度
x:= [4]int{1,2,3,4}
// or
var y = [4]int

// 不指定长度,由元素个数决定长度
x:= [...]int{1,2,3,4}

在Go中,数组的长度是固定的,创建后不可修改。所以一般情况下用切片比较 方便。切片的长度是可变的,比较好用。

初始化一个切片由几种方法。
代码语言:javascript
复制
// 1 、直接通过元素初始化
x:= []int{1,2,3,4}
//2、 通过数组生成切片
arr:= [...]int{1,2,3,4}
// 表示以arr的下标0-3 生成一个新的切片
x:= arr[0:4] // 等价于 arr[:4] arr[:] 

// 3 通过make初始化
x:= make([]int,4,4) // 初始化一个长度为4 ;容量为4的切片

需要注意的是,切片底层是指向一个数组的。参考以下代码

代码语言:javascript
复制
func main() {
	x := [...]int{1, 2, 3, 4}
	y := x[:]
	y[2] = 1
	fmt.Println(x, y)// [1 2 1 4] [1 2 1 4]
}

我们可以看到修改切片的值,数组和切片都同样被改变。但是有一种情况是不同的,就是如果我们对切片进行元素追加,此时切片就指向另一个新的底层匿名数组,此时和原数组就没有关系了

如下:

代码语言:javascript
复制
func main() {
	x := [...]int{1, 2, 3, 4}
	y := x[:]
	y = append(y, 5)
	y[2] = 222
	fmt.Println(x, y) // [1 2 3 4] [1 222 3 4 5]
}

简单总结就是:切片是指向一个底层数组,如果这个底层数组容量不足时,切片会自动扩容,指向另一个新的底层数组,和原来的数组就没有关系

数组和切片作为参数传递给函数

  • 值传递
代码语言:javascript
复制
func Test(arr [4]int) {
	arr[1] = 888
}
x := [...]int{1, 2, 3, 4}
Test(x) // x: [1,2,3,4] 值传递不会影响到x的值
  • 传递地址
代码语言:javascript
复制
func Test(arr *[4]int) {
	arr[1] = 888
}
x := [...]int{1, 2, 3, 4}
Test(&x) // [1,888,3,4] 传递地址,函数内修改会影响外部

切片有点特殊。切片本质上是一个包含3个属性的结构体。3个属性分别是,切片的长度、切片的容量、一个指针指向底层数组

代码语言:javascript
复制
// y是切片
unsafe.Sizeof(y)// 24
// 类似
type Slice struct {
	len int //切片长度
	cap int // 切片容量
	point *[](int) // 底层数组的指针
}
  • 值传递

需要注意的是,我们通过传递切片也是值传递的(切片本身被拷贝),函数内的修改切片是修改切片的数组指针属性指向的底层数组的, 所以对应底层数组也会被修改。所以有一种错觉,怎么切片值传递,切片值出来被修改了呢。

代码语言:javascript
复制
func Test(arr []int) {
	arr[1] = 888
}
func main() {
	x := [...]int{1, 2, 3, 4}
	y := x[:]
	Test(y)
	fmt.Println(x) // x [1,888,3,4] 看上去是修改了原切片,其实只是函数内部通过拷贝的底层数组的地址修改了对应底层数组的值
}

但是,如果我们在函数内对切片进行追加,此时,我们再去修改,就是修改了另一个底层数组。这时候原切片和原数组,都不会被修改到了。

代码语言:javascript
复制
func Test(arr []int) {
	arr[1] = 888
	arr = append(arr, 222)
}
func main() {
	x := [...]int{1, 2, 3, 4}
	y := x[:]
	Test(y)
	fmt.Println(x, y)// 这里x y 都不会被修改
}

所以,切片作为函数参数传递,也是符合Go语言的函数参数值传递的理念。

  • 地址传递

切片也是可以地址传递的

代码语言:javascript
复制
func Test(arr *([]int)) {
	(*arr) = append(*arr, 222)
}
func main() {
	x := [...]int{1, 2, 3, 4}
	y := x[:]
	Test(&y)
	fmt.Println(x, y)// [1 2 3 4] [1 2 3 4 222]
}

有之前的分析,就很好理解了。切片传递的是指针,函数内对切片追加,修改就是修改了原切片的指向底层数组的指针指向,指向我们新生成的指针。所以main函数中, 我们打印切片,发现打印值就是我们修改的值,而原数组也不会被更改了。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Go之数组/切片
    • 初始化
      • Go中初始化一个数组如下
      • 初始化一个切片由几种方法。
    • 数组和切片作为参数传递给函数
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档