这是我参与更文挑战的第8天,活动详情查看:更文挑战
大家好,我是 @洛竹
本文首发于 洛竹的官方网站
本文翻译自 Golang tutorial series
本文同步于公众号『洛竹早茶馆』,转载请联系作者。
创作不易,养成习惯,素质三连!
切片是数组上面的一个方便、灵活和强大的包装器。切片并不拥有自己的任何数据。它们只是对现有数组的引用。
创建切片
一个具有 T 类型元素的切片用 []T
表示。
package main
import (
"fmt"
)
func main() {
a := [5]int{76, 77, 78, 79, 80}
var b []int = a[1:4] // 创建一个 a[1] 到 a[3] 的切片
fmt.Println(b)
}
语法a[start:end]
从数组 a
中创建一个切片,从索引 start
开始到索引 end
-1。所以在上述程序中,
a[1:4]创建了一个从索引 1 到 3 的数组
a的切片。因此切片
b的值是
[77 78 79]`。
让我们来看看创建切片的另一种方法。
package main
import (
"fmt"
)
func main() {
c := []int{6, 7, 8} // 创建一个数组并返回切片的索引
fmt.Println(c)
}
在上述程序中,c := []int{6, 7, 8}
创建了一个包含 3 个整数的数组,并返回一个存储在 c 中的切片引用。
修改一个切片
一个切片并不拥有自己的任何数据。它只是底层数组的一个代表。对切片所做的任何修改都会反映在底层数组中。
package main
import (
"fmt"
)
func main() {
darr := [...]int{57, 89, 90, 82, 100, 78, 67, 69, 59}
dslice := darr[2:5]
fmt.Println("array before",darr)
for i := range dslice {
dslice[i]++
}
fmt.Println("array after",darr)
}
在上述程序中,我们从数组的索引 2、3、4 创建 dslice
。for 循环将这些索引的值增加 1。当我们在 for 循环后打印数组时,我们可以看到切片的变化已经反映在数组中。该程序的输出是
array before [57 89 90 82 100 78 67 69 59]
array after [57 89 91 83 101 78 67 69 59]
当一些切片共享同一个底层数组时,每个切片的变化都会反映在数组中。
package main
import (
"fmt"
)
func main() {
numa := [3]int{78, 79 ,80}
nums1 := numa[:] // 创建一个包含数组中所有元素的片断
nums2 := numa[:]
fmt.Println("array before change 1",numa)
nums1[0] = 100
fmt.Println("array after modification to slice nums1", numa)
nums2[1] = 101
fmt.Println("array after modification to slice nums2", numa)
}
在 numa[:]
中,缺少开始和结束值。start 和 end 的默认值分别为 0
和 len(numa)
。两个切片 nums1
和 nums2
共享同一个数组。该程序的输出是
array before change 1 [78 79 80]
array after modification to slice nums1 [100 79 80]
array after modification to slice nums2 [100 101 80]
从输出结果来看,很明显,当切片共享同一个数组时。对切片所做的修改会反映在数组中。
切片的长度和容量
切片的长度是切片中元素的数量。切片的容量是指从创建分片的索引开始的底层数组中的元素数。
让我们写一些代码来更好地理解这一点。
package main
import (
"fmt"
)
func main() {
fruitarray := [...]string{"apple", "orange", "grape", "mango", "water melon", "pine apple", "chikoo"}
fruitslice := fruitarray[1:3]
fmt.Printf("length of slice %d capacity %d", len(fruitslice), cap(fruitslice)) // 切的长度为 2,容量为 6
}
在上面的程序中,fruitslice
是由 fruitarray
的索引 1 和 2 创建的。因此,fruitslice
的长度是 2。
fruitarray
的长度是 7。fruiteslice
是从 fruitarray
的索引 1 创建的。因此,fruitslice
的容量是 fruitarray' 中从索引 1 开始的元素数量,即从
orange 开始,这个值是
6。因此,
fruitslice` 的容量是 6。程序 打印出 length of slice 2 capacity 6。
一个切片可以被重新切割到它的容量。任何超过这个容量的部分都会导致程序出现运行时错误。
package main
import (
"fmt"
)
func main() {
fruitarray := [...]string{"apple", "orange", "grape", "mango", "water melon", "pine apple", "chikoo"}
fruitslice := fruitarray[1:3]
fmt.Printf("length of slice %d capacity %d\n", len(fruitslice), cap(fruitslice)) // 长度为 2,容量为 6
fruitslice = fruitslice[:cap(fruitslice)] // 重新分割切片,直到其容量。
fmt.Println("After re-slicing length is",len(fruitslice), "and capacity is",cap(fruitslice))
}
在上述程序中,fruitslice
被重新f分割成到其容量。上述程序的输出。
length of slice 2 capacity 6
After re-slicing length is 6 and capacity is 6
使用 make 创建切片
func make([]T, len, cap) []T 可以通过传递类型、长度和容量来创建一个切片。容量参数是可选的,默认为长度。make 函数创建一个数组,并返回对它的切片的引用。
package main
import (
"fmt"
)
func main() {
i := make([]int, 5, 5)
fmt.Println(i)
}
当使用 make 创建一个切片时,这些值默认为零。上述程序将输出 [0 0 0 0]
。