Go基础编程——切片slice

切片SIice
1、其 本 身 并 不 是 数 组 , 它 指 向底层数组
2、作 为 变 长 数 组 的 替代 方 案 , 可 以 关 联底层 数 组 的 局 部 或 全 部
3、为 引 用 类 型
4、可 以 直 接 创 建 或从底层 数 组 获 取 生 成
5、使 用 len() 获 取 元 个 数,cap() 获 取 容 量
6、一 般 使 用 make() 创 建
7、如 果 多 个Slice 指 向 相 同 底 叟 组 , 其 中 一 个 的 值 改 变 会 影 响 全 部
8、make(()T, Jen, cap)
其 中 ( ap 可 以 省 略 , 则和len 的 值 相 同
len 表 示 存储的 元素个 数 ,cap表示容量
一个Slice的令名如下

var a []int

使用切片Slice截取数组的使用案例:

a :=[10]int{1,2,3,4,5,6,7,8,9,10}
fmt.Println(a)
s:=a[5:10]
fmt.Println(s)

运行结果如下:

[1 2 3 4 5 6 7 8 9 10]
[6 7 8 9 10]

值得注意的是——[5:10]包含起始端,不包含终止端。也就是数学上常说的左闭右开。
其实还有两种方法可以实现把后面的数据全部截取

s:=a[5:]
s:=a[5:len(a)]

其实后一种方法等价于前一种,在比较好的编辑器上会提示
也就是说len(a)在这里属于多余的索引。
同样去前5个的方法:

s:=a[:5]

使用make()函数声明Slice的方法

s1:=make([]int,3,10)

关于第一个参数3是初始化为3个int类型的数据,容量是10个,当超出10的时候,Go语言机制中,容量翻倍成20,当达到21个时超出20个了,容量会继续翻倍成为40个,这些都是Go语言底层的机制实现的。这里记住一点计算机重新分配内存地址是一种效率比较低的行为,尽量让容量一次满足条件。还有当我们不设置第三个参数10的时候,也是可以的,这时候默认的最大容量就是3个。

Slice与底层数组之间的关系
下边实现截取Slice_a的方法

a:=[]byte{'a','b','c','d','e','f','g','h','i','j','k'}
sa:=a[2:5]
fmt.Println(a)
fmt.Println(string(sa))

截取Slice_b方法如下:

a:=[]byte{'a','b','c','d','e','f','g','h','i','j','k'}
sb:=a[3:5]
fmt.Println(a)
fmt.Println(string(sb))

Reslice
1、Reslice 时 索 引 以 被Slice的 片 为 准
2、索 引 不 可 以 超 过 被 slice 的 切 片 的 容 量 cap() 值
3、索 引 越 界 不 会 导 致 底 层 数 组 的 重 新 分 配 而 是 引 发错误
Append(重点)
1、可 以 在Slice尾 部 追 加 元 素
2、可 以 将 一 个 slice 追加 在 另 一 个slice 尾 部
3、如 果 最 终 长 度 未 超 过 追 加 到 Slice 的 容 量 则 返 回 原 始Slice
4、如 果 超 过 追 加 到 的Slice的 容 量 则 将 重 新分配数组并拷贝原 始 数 据
Copy
以下程序实现Reslice:

a:=[]byte{'a','b','c','d','e','f','g','h','i','j','k'}
sa:=a[2:5]
sb:=sa[1:3]
fmt.Println(a)
fmt.Println(string(sa))
fmt.Println(string(sb))

string(sb)运行结果
依旧是de,这就是Reslice
这里引出一个之前对于Slice理解的一个误区,看下边程序以及运行结果:

sb:=sa[3:5]

运行结果是:

fg

这里会有些误解认为sa只包含cde三个元素,怎么会再次截取的时候会超出这三个呢,用程序来帮助理解是最好的办法。

fmt.Println(len(sa),cap(sa))

运行结果是

3 9

就知道它的容量是9个,长度是3个。只是sa包含cde三个而已,Slice指向的是个连续的内存块。

a:=[]byte{'a','b','c','d','e','f','g','h','i','j','k'}
sa:=a[2:5]
sb:=sa[3:11]
fmt.Println(a)
fmt.Println(len(sa),cap(sa))
fmt.Println(string(sa))
fmt.Println(string(sb))

运行结果:

panic: runtime error: slice bounds out of range

就报错了,说超出容量了。由前边的cap(sa)我们知道,最大容量是9个,这里就要求把程序中的[3:11]改为[3:9]

接下来是这节的重点,使用append()函数在Slice后面追加元素

s1:=make([]int,3,5)
fmt.Printf("%v,%p\n",s1,s1)
s1=append(s1,1,2,1,3)
fmt.Printf("%v,%p\n",s1,s1)

运行结果

0xc042066030
[0 0 0 1 2 1 3],0xc04206e0a0

添加之后显示它的值和内存地址,可以看内存地址是不一样的,值不一样,这里的内存地址不一样的原因是,原来的最大容量5个,初始值的个数是3个在添加4个之后,最大容量翻倍变成10个。这时候的内存地址肯定不一样,因为Go语言的底层机制重新分配了一些内存给它。
想内存地址一样,

s1:=make([]int,3,10)

这时候的运行结果如下

[0 0 0],0xc04206e0a0
[0 0 0 1 2 1 3],0xc04206e0a0

内存地址变成一样了。
接下来说一个重点,当两个切片共享同一个元素(共同指向同一个元素)时,只要其中一个切片改变这个元素,另外一个切片也会随着改变。
看如下程序以及运行结果:

a:=[]int{1,2,3,4,5,6,7}

s1:=a[2:5]
s2:=a[0:3]
   fmt.Println(a,s1,s2)
s1[0]=9
fmt.Println(a,s1,s2)

运行结果

[1 2 3 4 5 6 7] [3 4 5] [1 2 3]
[1 2 9 4 5 6 7] [9 4 5] [1 2 9]

当然也把原始的数组改变了。这里还有要注意的地方就是使用append改变s2时,当append()后超出原有的容量,Go语言的底层机制会给s2重新分配内存地址,它就不是原来的地址,这时候s1[0]=9对于s2来说是不影响的。看程序如下,以及它的运行结果就可以解释这个了,这是我们使用append时特别注意的地方。

a:=[]int{1,2,3,4,5,6,7}

s1:=a[2:5]
s2:=a[0:3]
   fmt.Println(a,s1,s2)
   s2=append(s2,55,55,55,55,55,55,55,55,55,55,55,55)
s1[0]=9
fmt.Println(a,s1,s2)

运行结果如下

[1 2 3 4 5 6 7] [3 4 5] [1 2 3]
[1 2 9 4 5 6 7] [9 4 5] [1 2 3 55 55 55 55 55 55 55 55 55 55 55 55]

可以看到原来s2的3没有被改变,这里s2的3已经不是和s1指向同一块地址了,所以没法改变它,用程序输出s1和s2指向的内存看看就知道了。

fmt.Printf("%p,%p\n",s1,s2)

运行结果如下

0xc042070050,0xc042072080

最后谈谈数组的copy函数

s1:=[]int{1,2,3,4,5,6}
s2:=[]int{7,8,9}
copy(s1,s2)
fmt.Println(s1)

运行结果

[7 8 9 4 5 6]

反过来s1复制到s2中

copy(s2,s1)
fmt.Println(s2)

运行结果是

[1 2 3]

容量长的切片复制到容量短的切片是,以容量短的为准,换句话说以容器为准。
再说说值复制一部分是如何实现的?
假如只复制s1中的4,5两个元素到s2中

copy(s2,s1[3:5])
fmt.Println(s2)

运行结果

[4 5 9]

同样复制的时候在容器中默认从下标为0的位置开始放置复制过来的元素,当然也可以制定它放置的具体位置,比如上例中的复制元素4,5我想把它们放置在第二个和第三个位置,操作如下:

copy(s2[1:3],s1[3:5])

运行结果:

[7 4 5]

这样就实现了想要的。
思考以下问题:
如何将一个Slice指向一个完整的底层数组,而不是部分底层数组?
接下来我就是来实现它:

s1:=[]int{1,2,3,4,5,6}
s2:=[]int{7,8,9}
      copy(s2[1:3],s1[3:5])
      s3:=s1[0:]
fmt.Println(s2)
fmt.Println(s3)

其中s3就实现了上述题目的要求。
当然也可以使用

s3:=s1[0:5]
s3:=s1[0:]
s3:=s1[:]

这三种方式完成。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章