内容简介:这一节,我们来讨论更多关于上面这段代码声明了一个如何声明空切片?有两种方式:
这一节,我们来讨论更多关于 Slice
的用法。
nil
切片与空切片
nil
切片
var s []int fmt.Println(s == nil) // 输出 true fmt.Println(len(s),cap(s)) // 输出:0 0 复制代码
上面这段代码声明了一个 nil
切片 s
,其实,切片的零值就是 nil
。为什么?通过上一节我们知道,因为切片就是一个数组的引用。切片的类型在初始化时已经确认,就是 []Type
,上面的代码就声明了 []int
类型的 nil
切片 s
。 nil
切片的指向底层数组的指针为 nil
。
空切片
如何声明空切片?有两种方式:
// 1、使用 make 创建空的整型切片 s := make([]int, 0) // 2、使用切片字面量创建空的整型切片 s := []int{} fmt.Println(s) // 输出:[] fmt.Println(len(s),cap(s)) // 输出:0 0 复制代码
通过上面代码可以得出,与 nil
切片一样,空切片的长度和容量也都是0,说明切片底层的数组大小为0,是一个空数组(没有分配任何的存储空间)。
不管是使用 nil
切片还是空切片,对其调用内置函数 append
、 len
和 cap
的效果都是一样的。
copy
函数
Go提供了内置函数 copy
,可以讲一个切片复制到另一个切片。函数原型:
func copy(dst, src []Type) int 复制代码
dst
是目标切片, src
是源切片,函数返回两者长度的最小值。
var s1 []int s2 := []int{1, 2, 3} s3 := []int{4, 5, 6, 7} s4 := []int{1, 2, 3} // 1、 n1 := copy(s1, s2) fmt.Printf("n1=%d, s1=%v, s2=%v\n", n1, s1, s2) fmt.Println("s1 == nil", s1 == nil) // 2、 n2 := copy(s2, s3) fmt.Printf("n2=%d, s2=%v, s3=%v\n", n2, s2, s3) // 3、 n3 := copy(s3, s4) fmt.Printf("n3=%d, s3=%v, s4=%v\n", n3, s3, s4) 复制代码
输出 :
n1=0, s1=[], s2=[1 2 3] s1 == nil true n2=3, s2=[4 5 6], s3=[4 5 6 7] n3=3, s3=[1 2 3 7], s4=[1 2 3] 复制代码
上面代码生声明了 nil
切片 s1
和三个非空切片 s2
、 s3
和 s4
。从第一块代码块可以看到,因为 s1
是 nil
切片,执行完 copy
操作之后, s1
依然还是 nil
。这有别于 append
函数:
var s1 []int s2 := []int{1, 2, 3} s1 = append(s1, s2...) fmt.Println(s1) // 输出:[1 2 3] 复制代码
第二段代码:由于 s2
的长度是3, s3
的长度是4,所以执行 copy
操作只会从 s3
复制3个元素至 s2
。 copy
只会复制,不会追加。 第三段代码也是同样的道理。
函数间传递切片
切片在函数间以值的方式传递。由于切片的尺寸很小(在 64 位架构的机器上,一个切片需要 24 字节的内存:指针字段、长度和容量字段各需要 8 字节),在函数间复制和传递切片成本也很低。切片发生复制时,底层数组不会被复制,数组大小也不会有影响。
func main() { s := []int{0, 1, 2, 3, 4, 5} fmt.Printf("%p\n", &s) modify(s) fmt.Println(s) } func modify(s []int) { fmt.Printf("%p\n", &s) s[1] = 10 } 复制代码
输出 :
0xc000086020 0xc000086040 [0 10 2 3 4 5] 复制代码
我们可以看到,原切片地址和传递之后的切片的地址是不一样的,说明发生了复制;在函数 modify
中修改了切片一个值,原切片的值也随之改变了,说明这两个切片是共享底层数组的。 在函数间传递切片非常高效,而且不需要传递指针和处理复杂的语法,只需要复制切片,按自己的业务修改数据,最后传递回一个新的切片副本即可,这也是为什么函数间使用切片传参,而不是数组传参的原因。
删除切片中的元素
Go没有提供删除切片元素的函数,然而,我们可以使用一些“黑科技”达到这样的目的。
s := []int{1, 2, 3, 4, 5, 6} s = append(s[:2], s[3:]...) // 删除索引为2的元素 fmt.Println(s) 复制代码
输出:
[1 2 4 5 6] 复制代码
通过这两节详解,相信你已经掌握了 Slice
,建议大家要多多练习!
关注公众号「Golang来了」,获取最新文章!
以上所述就是小编给大家介绍的《非懂不可的Slice(二)-- 就要学习Go语言》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JavaScript语言精髓与编程实践
周爱民 / 电子工业出版社 / 2012-3 / 79.00元
《JavaScript语言精髓与编程实践(第2版)》详细讲述JavaScript作为一种混合式语言的各方面特性,包括过程式、面向对象、函数式和动态语言特性等,在动态函数式语言特性方面有着尤为细致的讲述。《JavaScript语言精髓与编程实践(第2版)》的主要努力之一,就是分解出这些语言原子,并重现将它们混合在一起的过程与方法。通过从复杂性到单一语言特性的还原过程,读者可了解到语言的本质,以及“层......一起来看看 《JavaScript语言精髓与编程实践》 这本书的介绍吧!