在 Go 语言中,slice 是一个轻量级的数据结构,用于管理一组具有相同类型的元素序列。Slice 提供了一种方便且灵活的方式来操作序列数据。
在 Go 中,一个 slice 包含三个部分:
package main
import (
"fmt"
)
func main() {
// 创建一个底层数组
array := [5]int{1, 2, 3, 4, 5}
// 使用切片来引用底层数组的一部分
slice := array[1:4] // 从索引为1的元素开始,到索引为3的元素结束,但不包括索引为4的元素
// 打印切片的指针、长度和容量
fmt.Printf("Pointer: %p, Length: %d, Capacity: %d\n", &slice[0], len(slice), cap(slice))
// 修改切片中的元素
slice[0] = 10
// 打印底层数组和切片中的元素
fmt.Println("Array:", array)
fmt.Println("Slice:", slice)
}
package main
import "fmt"
func main() {
// 创建一个底层数组
array := [5]int{1, 2, 3, 4, 5}
fmt.Println("Capacity of array after appending:", cap(array)) // 输出:Capacity of array after appending: 5
// 创建切片1,引用数组的一部分
slice1 := array[1:4]
fmt.Println("Slice 1:", slice1) // 输出:Slice 1: [2 3 4]
// 修改切片1中的元素,同时底层数组也被修改
slice1[0] = 10
fmt.Println("Array after modifying slice 1:", array) // 输出:Array after modifying slice 1: [1 10 3 4 5]
// 创建切片2,引用切片1的一部分
slice2 := slice1[1:3]
fmt.Println("Slice 2:", slice2) // 输出:Slice 2: [3 4]
// 修改切片2中的元素,同时切片1和底层数组也被修改
slice2[1] = 20
fmt.Println("Array after modifying slice 2:", array) // 输出:Array after modifying slice 2: [1 10 3 20 5]
fmt.Println("Slice 1 after modifying slice 2:", slice1) // 输出:Slice 1 after modifying slice 2: [10 3 20]
fmt.Println("Capacity of slice 1 after appending:", cap(slice1)) // 输出:Capacity of slice 1 after appending: 4
// 动态增长切片 向切片 slice1 中添加元素 6 和 7
slice1 = append(slice1, 6, 7)
fmt.Println("Slice 1 after appending:", slice1) // 输出:Slice 1 after appending: [10 3 20 6 7]
fmt.Println("Array after appending to slice 1:", array) // 输出:Array after appending to slice 1: [1 10 3 20 6]
// 注意:切片的容量不变,仍然指向原底层数组的部分
fmt.Println("Capacity of slice 1 after appending:", cap(slice1)) // 输出:Capacity of slice 1 after appending: 8
fmt.Println("Capacity of array after appending:", cap(array)) // 输出:Capacity of array after appending: 5
}
这个运行结果说明了切片和底层数组的特性,以及切片操作的影响:
array
的容量为 5。slice1
,它引用了数组的一部分,即 [2 3 4]
。slice1
中的第一个元素为 10
,底层数组也相应地被修改。slice2
,它引用了切片1的一部分,即 [3 4]
。slice2
中的第二个元素为 20
,底层数组和切片1也相应地被修改。append()
向切片1 slice1
中添加了元素 6
和 7
。slice1
的容量,发现容量在追加元素后变为了 8
。当我们在同一 slice 上创建不同的切片时,它们是否共享同一个底层数组呢?我们来看看以下示例代码:
package main
import "fmt"
func main() {
// 创建一个切片 slice1
slice1 := []int{1, 2, 3, 4, 5}
// 创建 slice1 的两个切片:slice2 和 slice3
slice2 := slice1[1:3]
slice3 := slice1[2:5]
// 修改 slice2 的元素值
slice2[0] = 10
// 输出 slice1、slice2 和 slice3 的内容
fmt.Println("slice1:", slice1) // 输出:slice1: [1 10 3 4 5]
fmt.Println("slice2:", slice2) // 输出:slice2: [10 3]
fmt.Println("slice3:", slice3) // 输出:slice3: [3 4 5]
}
你的代码创建了一个切片 slice1
,然后又基于 slice1
创建了两个新的切片 slice2
和 slice3
。接着,修改了 slice2
的第一个元素的值为 10
。最后,输出了三个切片的内容。
这个结果说明了切片的特性:
slice2
和 slice3
时,它们指向的是 slice1
中相应索引范围的元素。所以 slice2
中的修改影响了 slice1
,而 slice3
没有受到影响。切片是 Go 中非常常用的数据结构,它们在很多场景下都能发挥重要作用,例如:
下面是一个演示切片应用场景的示例代码:
package main
import "fmt"
// 动态数组
func dynamicArray() {
// 声明一个切片
var numbers []int
// 使用 append() 函数动态增加元素
numbers = append(numbers, 1)
numbers = append(numbers, 2, 3, 4)
fmt.Println("Dynamic Array:", numbers)
}
// 函数参数和返回值
func processSlice(input []int) []int {
// 对切片进行操作
for i := range input {
input[i] *= 2
}
return input
}
// 数据过滤和操作
func filterSlice(input []int) []int {
var filtered []int
for _, num := range input {
if num%2 == 0 {
filtered = append(filtered, num)
}
}
return filtered
}
func main() {
// 动态数组
dynamicArray()
// 函数参数和返回值
original := []int{1, 2, 3, 4, 5}
processed := processSlice(original)
fmt.Println("Processed Slice:", processed)
// 数据过滤和操作
data := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
filtered := filterSlice(data)
fmt.Println("Filtered Slice:", filtered)
}
运行结果:
这个示例展示了切片在不同场景下的应用:
append()
函数动态地向切片中添加元素,实现了动态数组的功能。processSlice()
函数接受一个切片作为参数,对其进行操作后返回。这种方式避免了对大量数据进行拷贝,提高了程序性能。filterSlice()
函数对切片中的元素进行过滤,仅保留偶数。这样可以方便地对数据进行操作,提高了代码的可读性和可维护性。