gpt4 book ai didi

golang中的空slice案例

转载 作者:qq735679552 更新时间:2022-09-28 22:32:09 31 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章golang中的空slice案例由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

golang中允许对值为 nil 的 slice 添加元素 。

?
1
2
3
4
5
package main
func main() {
  var s []int
  s = append(s, 1)
}

运行成功~ 。

补充:golang slice 详解 。

1、数组切片的使用

  。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
func main() {
     //1.基于数组创建数组切片
     var array [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
     var slice = array[1:7] //array[startIndex:endIndex] 不包含endIndex
     //2.直接创建数组切片
     slice2 := make([]int, 5, 10)
     //3.直接创建并初始化数组切片
     slice3 := []int{1, 2, 3, 4, 5, 6}
     //4.基于数组切片创建数组切片
     slice5 := slice3[:4]
     //5.遍历数组切片
     for i, v := range slice3 {
         fmt.Println(i, v)
     }
     //6.len()和cap()
     var len = len(slice2) //数组切片的长度
     var cap = cap(slice)  //数组切片的容量
     fmt.Println("len(slice2) =", len)
     fmt.Println("cap(slice) =", cap)
     //7.append() 会生成新的数组切片
     slice4 := append(slice2, 6, 7, 8)
     slice4 = append(slice4, slice3...)
     fmt.Println(slice4)
     //8.copy() 如果进行操作的两个数组切片元素个数不一致,将会按照个数较小的数组切片进行复制
     copy(slice2, slice3) //将slice3的前五个元素复制给slice2
     fmt.Println(slice2, slice3)
}

2、数组切片数据结构分析

  。

数组切片slice的数据结构如下,一个指向真实array地址的指针ptr,slice的长度len和容量cap 。

golang中的空slice案例

golang中的空slice案例

?
1
2
3
4
5
6
// slice 数据结构
type slice struct {
     array unsafe.Pointer
     len   int           
     cap   int           
}

当传参时,函数接收到的参数是数组切片的一个复制,虽然两个是不同的变量,但是它们都有一个指向同一个地址空间的array指针,当修改一个数组切片时,另外一个也会改变,所以数组切片看起来是引用传递,其实是值传递.

3、append()方法解析

  。

3.1 数组切片不扩容的情况 。

运行以下代码思考一个问题:s1和s2是指向同一个底层数组吗?

?
1
2
3
4
5
6
7
8
9
10
func main() {
     array := [20]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
     s1 := array[:5]
     s2 := append(s1, 10)
     fmt.Println("s1 =", s1)
     fmt.Println("s2 =", s2)
     s2[0] = 0
     fmt.Println("s1 =", s1)
     fmt.Println("s2 =", s2)
}

输出结果:

s1 = [1 2 3 4 5] 。

s2 = [1 2 3 4 5 10] 。

s1 = [0 2 3 4 5] 。

s2 = [0 2 3 4 5 10] 。

由第一行和第二行结果看来,似乎这是指向两个不同的数组;但是当修改了s2,发现s1也跟着改变了,这又表明二者是指向同一个数组。到底真相是怎样的呢?

运行以下代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import (
     "fmt"
     "unsafe"
)
type Slice struct {
     ptr unsafe.Pointer // Array pointer
     len int            // slice length
     cap int            // slice capacity
}
func main() {
     array := [20]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
     s1 := array[:5]
     s2 := append(s1, 10)
     s2[0] = 0
     // 把slice转换成自定义的 Slice struct
     slice1 := (*Slice)(unsafe.Pointer(&s1))
     fmt.Printf("ptr:%v len:%v cap:%v \n", slice1.ptr, slice1.len, slice1.cap)
     slice2 := (*Slice)(unsafe.Pointer(&s2))
     fmt.Printf("ptr:%v len:%v cap:%v \n", slice2.ptr, slice2.len, slice2.cap)
}

输出结果:

ptr:0xc04205e0a0 len:5 cap:20 。

ptr:0xc04205e0a0 len:6 cap:20 。

由结果可知:ptr指针存储的是数组中的首地址的值,并且这两个值相同,所以s1和s2确实是指向同一个底层数组.

但是,这两个数组切片的元素不同,这个可以根据首地址和数组切片长度len来确定不同的数组切片应该包含哪些元素,因为s1和s2虽然指向同一个底层数组,但是二者的len不同。通过这个demo,也验证了数组切片传参方式也是值传递.

3.2 数组切片扩容的情况:

运行以下代码,思考与不扩容情况的不同之处,以及为什么 。

?
1
2
3
4
5
6
7
8
9
func main() {
     s1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
     s2 := append(s1, 10)
     fmt.Println("s1 =", s1)
     fmt.Println("s2 =", s2)
     s2[0] = 0
     fmt.Println("s1 =", s1)
     fmt.Println("s2 =", s2)
}

输出结果:

s1 = [1 2 3 4 5 6 7 8 9] 。

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

s1 = [1 2 3 4 5 6 7 8 9] 。

s2 = [0 2 3 4 5 6 7 8 9 10] 。

根据结果我们发现,修改s2后,s1并未改变,这说明当append()后,s1和s2并未指向同一个底层数组,这又是为什么呢?

同样,我们接着运行以下代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import (
     "fmt"
     "unsafe"
)
type Slice struct {
     ptr unsafe.Pointer // Array pointer
     len int            // slice length
     cap int            // slice capacity
}
func main() {
     s1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
     s2 := append(s1, 10)
     fmt.Println("s1 =", s1)
     fmt.Println("s2 =", s2)
     s2[0] = 0
     fmt.Println("s1 =", s1)
     fmt.Println("s2 =", s2)
     // 把slice转换成自定义的 Slice struct
     slice1 := (*Slice)(unsafe.Pointer(&s1))
     fmt.Printf("ptr:%v len:%v cap:%v \n", slice1.ptr, slice1.len, slice1.cap)
     slice2 := (*Slice)(unsafe.Pointer(&s2))
     fmt.Printf("ptr:%v len:%v cap:%v \n", slice2.ptr, slice2.len, slice2.cap)
}

输出结果:

s1 = [1 2 3 4 5 6 7 8 9] 。

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

s1 = [1 2 3 4 5 6 7 8 9] 。

s2 = [0 2 3 4 5 6 7 8 9 10] 。

ptr:0xc04207a000 len:9 cap:9 。

ptr:0xc04207c000 len:10 cap:18 。

由结果可知:append()后,s1和s2确实指向了不同的底层数组,并且二者的数组容量cap也不相同了.

过程是这样的:当append()时,发现数组容量不够用,于是开辟了新的数组空间,cap变为原来的两倍,s2指向了这个新的数组,所以当修改s2时,s1不受影响 。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我。如有错误或未考虑完全的地方,望不吝赐教.

原文链接:https://blog.csdn.net/ma2595162349/article/details/109016324 。

最后此篇关于golang中的空slice案例的文章就讲到这里了,如果你想了解更多关于golang中的空slice案例的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com