• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    golang中的空slice案例

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

    package main 
    func main() {
     var s []int
     s = append(s, 1)
    }

    运行成功~

    补充:golang slice 详解

    一、数组切片的使用

    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)
    }
    

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

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

    // slice 数据结构
    type slice struct {
    	array unsafe.Pointer 
    	len   int            
    	cap   int            
    }

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

    三、append()方法解析

    3.1 数组切片不扩容的情况

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

    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也跟着改变了,这又表明二者是指向同一个数组。到底真相是怎样的呢?

    运行以下代码:

    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 数组切片扩容的情况:

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

    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并未指向同一个底层数组,这又是为什么呢?

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

    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不受影响

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

    您可能感兴趣的文章:
    • Golang 拷贝Array或Slice的操作
    • golang-切片slice的创建方式
    • Golang::slice和nil的对比分析
    • golang语言如何将interface转为int, string,slice,struct等类型
    • Golang中的Slice与数组及区别详解
    • golang中range在slice和map遍历中的注意事项
    • golang slice元素去重操作
    上一篇:Go语言切片前或中间插入项与内置copy()函数详解
    下一篇:Goland 断点调试Debug的操作
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    golang中的空slice案例 golang,中的,空,slice,案例,