我理解Go中数组和切片之间的区别.但我不明白的是为什么有数组是有帮助的.为什么数组类型定义指定长度和元素类型有帮助?为什么我们使用的每个"数组"都不能成为切片?
icz*_*cza 34
还有更多的阵列不仅仅是固定长度:它们是相当的,并且它们的值(未引用或指针类型).
在某些情况下,数组相对于切片有许多优点,所有这些优点一起证明了数组的存在(以及切片).我们来看看他们.(我甚至不计算数组是切片的构建块.)
1.具有可比性意味着你可以使用数组作为地图中的键,而不是切片.是的,你现在可以说,为什么不把切片比作,那么单凭这一点就不能证明两者的存在.切片上的平等定义不明确.常见问题:为什么地图不允许切片作为键?
他们没有实现平等,因为在这些类型上没有很好地定义平等; 有多个考虑因素涉及浅层与深层比较,指针与值的比较,如何处理递归类型等等.
2. 数组也可以提供更高的编译时安全性,因为可以在编译时检查索引边界(数组长度必须计算为可由类型值表示的非负常量int):
s := make([]int, 3)
s[3] = 3 // "Only" a runtime panic: runtime error: index out of range
a := [3]int{}
a[3] = 3 // Compile-time error: invalid array index 3 (out of bounds for 3-element array)
Run Code Online (Sandbox Code Playgroud)
3.同时传递或分配数组值将隐式地复制整个数组,因此它将与原始值"分离".如果传递切片,它仍然会复制切片头,但切片值(头部)将指向相同的支持数组.这可能是也可能不是你想要的.如果要从"原始"切片"分离"切片,则必须将内容(例如内置copy()函数)显式复制到新切片.
a := [2]int{1, 2}
b := a
b[0] = 10 // This only affects b, a will remain {1, 2}
sa := []int{1, 2}
sb := sa
sb[0] = 10 // Affects both sb and sa
Run Code Online (Sandbox Code Playgroud)
4.此外,由于数组长度是数组类型的一部分,因此具有不同长度的数组是不同的类型.一方面,这可能是"痛苦的屁股"(例如,你编写了一个接受类型参数的函数[4]int,你不能使用该函数来获取和处理类型的数组[5]int),但这也可能是一个优势:这可以用于显式指定预期的数组的长度.例如,您想要编写一个带有IPv4地址的函数,可以使用该类型对其进行建模[4]byte.现在你有一个编译时保证,传递给你的函数的值将只有4个字节,不多也不少(无论如何都是无效的IPv4地址).
5.与前面相关,数组长度也可以用于文档目的.一种类型[4]byte正确地说明IPv4有4个字节.一个rgb类型的可变[3]byte告诉有对每个颜色成分1个字节.在某些情况下,它甚至可以取出并可用,单独记录; 例如,在crypto/md5包中:md5.Sum()返回type的值,[Size]byte其中md5.Size是一个常量16:MD5校验和的长度.
6.在计划结构类型的内存布局时,它们也非常有用,请参阅JimB的答案,以及更详细和现实生活中的答案.
7.此外,由于切片是标题,并且它们(几乎)总是按原样传递(没有指针),因此语言规范对于指向切片的指针比指向数组的指针更具限制性.例如,规范为使用指向数组的指针提供了多个简写,而在切片的情况下同样会产生编译时错误(因为很少使用指向切片的指针,如果你仍然想要/必须这样做,你必须是明确处理它;在这个答案中阅读更多内容).
这样的例子是:
切片p指向数组:p[low:high]是一种简写(*p)[low:high].如果p是指向切片的指针,则这是编译时错误(spec:Slice表达式).
索引p指向数组的指针:p[i]是一种简写(*p)[i].如果p是指向切片的指针,则这是编译时错误(spec:Index expressions).
例:
pa := &[2]int{1, 2}
fmt.Println(pa[1:1]) // OK
fmt.Println(pa[1]) // OK
ps := &[]int{3, 4}
println(ps[1:1]) // Error: cannot slice ps (type *[]int)
println(ps[1]) // Error: invalid operation: ps[1] (type *[]int does not support indexing)
Run Code Online (Sandbox Code Playgroud)
8. 访问(单个)数组元素比访问切片元素更有效 ; 在切片的情况下,运行时必须经过隐式指针解除引用.另外"表达式len(s)并且cap(s)是常量,如果类型s是数组或指向数组的指针".
可能会很惊讶,但你甚至可以写:
type IP [4]byte
const x = len(IP{}) // x will be 4
Run Code Online (Sandbox Code Playgroud)
它是有效的,并且被评估和编译时,即使IP{}它不是一个常量表达式,所以例如const i = IP{}编译时错误!在此之后,以下内容也起作用甚至不足为奇:
const x2 = len((*IP)(nil)) // x2 will also be 4
Run Code Online (Sandbox Code Playgroud)
注意:当在完整数组和完整切片上进行测距时,可能根本没有性能差异,因为显然可以对其进行优化,以便切片标头中的指针仅被解除引用一次.有关详细信息/示例,请参阅阵列与切片:访问速度.
查看相关问题,其中可以使用数组/比切片更有意义:
为什么不能将Go切片用作Go贴图中的键,几乎可以将数组用作键?
这只是出于好奇: 切片可以包含自身,而数组则不能.(实际上,这个属性使得比较更容易,因为您不必处理递归数据结构).
必读博客:
| 归档时间: |
|
| 查看次数: |
1992 次 |
| 最近记录: |