
在Go语言中,数组是一种具有固定长度的同类型元素序列。数组的长度是其类型的一部分,这意味着[10]int和[20]int是两种完全不同的类型。
核心特性:
数组声明与传值示例:
package main
import "fmt"
func modifyArray(arr [5]int) {
arr[0] = 99 // 修改的是副本
fmt.Println("在函数内部修改后的数组副本:", arr)
}
func main() {
var arrValue = [5]int{1, 2, 3, 4, 5}
fmt.Println("原始数组:", arrValue)
modifyArray(arrValue) // 传递的是arrValue的副本
fmt.Println("函数调用后原始数组:", arrValue) // 原始数组未被修改
}输出:
立即学习“go语言免费学习笔记(深入)”;
原始数组: [1 2 3 4 5] 在函数内部修改后的数组副本: [99 2 3 4 5] 函数调用后原始数组: [1 2 3 4 5]
从示例中可以看出,modifyArray函数内部对数组的修改并未影响到main函数中的原始数组,这充分体现了数组的值类型特性和按值传递的语义。
与数组不同,切片提供了一种更强大、更灵活的数据结构,它代表了一个底层数组的连续片段。切片本身不存储任何数据,它只是对底层数组的一个“视图”。
核心特性:
切片声明与传值示例:
在Go语言中,使用字面量[]int{1, 5, 2, 3, 7}声明的变量,它是一个切片(Slice),而不是数组。切片字面量的声明方式与数组字面量相似,但省略了元素计数。
package main
import "fmt"
func modifySlice(s []int) {
s[0] = 99 // 修改的是底层数组的元素
fmt.Println("在函数内部修改后的切片:", s)
}
func main() {
var sliceValue = []int{1, 2, 3, 4, 5} // 这是一个切片
fmt.Println("原始切片:", sliceValue)
modifySlice(sliceValue) // 传递的是切片头的副本
fmt.Println("函数调用后原始切片:", sliceValue) // 原始切片被修改
}输出:
立即学习“go语言免费学习笔记(深入)”;
原始切片: [1 2 3 4 5] 在函数内部修改后的切片: [99 2 3 4 5] 函数调用后原始切片: [99 2 3 4 5]
从示例中可以看出,modifySlice函数内部对切片元素的修改,确实影响到了main函数中的原始切片。这是因为虽然切片头被复制了,但两个切片头都指向同一个底层数组,所以对底层数组的修改是共享的。
现在我们来解释最初的困惑:为什么sort.Ints(arrayValue)能修改变量,即使它看起来像一个数组。
根据Go标准库的定义,sort.Ints函数的签名如下:
func Ints(a []int)
它明确要求传入一个[]int类型的参数,即一个整型切片。
分析用户代码:
var av = []int{1,5,2,3,7} // 这行代码声明的是一个切片,不是数组!
fmt.Println(av)
sort.Ints(av) // 传入的是切片
fmt.Println(av)当av被声明为[]int{1,5,2,3,7}时,它实际上创建了一个切片。因此,将其传递给sort.Ints是完全合法的。sort.Ints函数接收到的是av切片头的一个副本,这个副本指向与av相同的底层数组。sort.Ints通过这个切片头访问并修改底层数组的元素,从而实现了对切片内容的排序。由于原始切片av和函数内部的切片都指向同一个底层数组,所以排序操作会直接反映在av上。
如果尝试将数组传递给 sort.Ints:
如果声明一个真正的数组并尝试传递给sort.Ints,Go编译器会报错,因为类型不匹配。
package main
import (
"fmt"
"sort"
)
func main() {
var arrValue = [5]int{1, 5, 2, 3, 7} // 这是一个数组
fmt.Println("原始数组:", arrValue)
// sort.Ints(arrValue) // 编译错误: cannot use arrValue (type [5]int) as type []int in argument to sort.Ints
// 如果要排序数组,需要先将其转换为切片
sort.Ints(arrValue[:]) // 通过切片表达式将数组转换为切片
fmt.Println("排序后数组(通过切片视图修改):", arrValue)
}输出:
立即学习“go语言免费学习笔记(深入)”;
原始数组: [1 5 2 3 7] 排序后数组(通过切片视图修改): [1 2 3 5 7]
通过arrValue[:],我们创建了一个指向arrValue底层数组的完整切片视图,然后将这个切片视图传递给sort.Ints。这样,sort.Ints就能修改底层数组,从而实现对原始数组的排序。
| 特性 | 数组 (Array) | 切片 (Slice) |
|---|---|---|
| 长度 | 固定长度,声明后不可改变 | 动态长度,可在运行时增长或缩短 |
| 类型 | 长度是类型的一部分,如[5]int和[10]int是不同类型 | 长度不是类型的一部分,[]int表示所有整型切片 |
| 内存 | 值类型,直接存储元素 | 引用类型,内部包含指针、长度和容量,指向底层数组 |
| 传参 | 按值传递,复制整个数组 | 复制切片头(指针、长度、容量),指向同一底层数组 |
| 用途 | 较少直接使用,常作为切片的底层存储 | Go中最常用的动态序列数据结构,功能强大 |
Go语言的数组和切片是两种截然不同的数据类型,尽管它们在语法上有些相似。数组是固定长度的值类型,按值传递时会进行完整复制;而切片是动态长度的引用类型(其头信息是值类型,但指向引用数据),按值传递时只复制切片头,因此可以修改其共享的底层数组。理解这些核心差异对于避免常见错误、编写高效且易于维护的Go代码至关重要。始终记住,[]int{...}是切片,而非数组。
以上就是Go语言中数组与切片的深度解析与实践的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号