
Go语言中的数组是一种具有固定长度的同类型元素序列。数组的长度在声明时确定,并且是其类型的一部分。这意味着[10]int和[20]int是两种完全不同的类型。
核心特性:
示例:
package main
import "fmt"
func modifyArray(arr [3]int) {
arr[0] = 99 // 修改的是副本
fmt.Println("函数内修改后的数组副本:", arr)
}
func main() {
var arr1 [3]int = [3]int{1, 2, 3}
fmt.Println("原始数组 arr1:", arr1)
modifyArray(arr1) // 传递的是 arr1 的副本
fmt.Println("函数调用后原始数组 arr1:", arr1) // 原始数组未被修改
var arr2 [3]int
arr2 = arr1 // 数组赋值是全量复制
arr2[0] = 100
fmt.Println("arr1 赋值给 arr2 后 arr1:", arr1)
fmt.Println("arr2:", arr2)
}输出:
立即学习“go语言免费学习笔记(深入)”;
原始数组 arr1: [1 2 3] 函数内修改后的数组副本: [99 2 3] 函数调用后原始数组 arr1: [1 2 3] arr1 赋值给 arr2 后 arr1: [1 2 3] arr2: [100 2 3]
切片是Go语言中一种更常用、更灵活的数据结构。它建立在数组之上,提供了一种动态长度的视图,可以引用底层数组的一部分或全部。切片本身并不是数组,它是一个结构体,包含三个字段:
核心特性:
示例:
package main
import "fmt"
func modifySlice(s []int) {
s[0] = 99 // 修改的是底层数组
fmt.Println("函数内修改后的切片:", s)
}
func main() {
var s1 []int = []int{1, 2, 3} // 这是一个切片字面量
fmt.Println("原始切片 s1:", s1)
modifySlice(s1) // 传递的是切片头信息的副本,但指针指向同一底层数组
fmt.Println("函数调用后原始切片 s1:", s1) // 原始切片被修改
var s2 []int
s2 = s1 // 切片赋值是头信息复制,共享底层数组
s2[0] = 100
fmt.Println("s1 赋值给 s2 后 s1:", s1)
fmt.Println("s2:", s2)
// 验证切片字面量与数组字面量的区别
// var arr3 [3]int = {1, 2, 3} // 编译错误,需要完整声明
var arr3 = [3]int{1, 2, 3} // 数组字面量
fmt.Printf("arr3 类型: %T, 值: %v\n", arr3, arr3)
var slc3 = []int{1, 2, 3} // 切片字面量
fmt.Printf("slc3 类型: %T, 值: %v\n", slc3, slc3)
}输出:
立即学习“go语言免费学习笔记(深入)”;
原始切片 s1: [1 2 3] 函数内修改后的切片: [99 2 3] 函数调用后原始切片 s1: [99 2 3] s1 赋值给 s2 后 s1: [100 2 3] s2: [100 2 3] arr3 类型: [3]int, 值: [1 2 3] slc3 类型: []int, 值: [1 2 3]
现在,我们来解决最初的困惑:为什么sort.Ints函数能够修改传递给它的变量?
问题中的代码片段:
var av = []int{1,5,2,3,7}
fmt.Println(av)
sort.Ints(av)
fmt.Println(av)关键点在于: var av = []int{1,5,2,3,7} 声明的 av 是一个切片,而不是一个数组。虽然它的字面量形式与数组字面量相似,但由于缺少了长度的指定(例如[5]int),它被Go编译器识别为切片字面量。
sort.Ints函数的签名如下:
func Ints(a []int)
这明确表示sort.Ints函数接收一个[]int类型的参数,即一个整数切片。
当av(一个切片)被传递给sort.Ints时,Go语言会按照值传递的规则,复制av的切片头信息(指针、长度、容量)。这个复制的头信息中的指针仍然指向av底层数组的相同内存位置。sort.Ints函数通过这个复制的指针,直接操作并修改了底层数组的元素顺序。因此,当函数返回后,av所引用的底层数组内容已经被排序,所以fmt.Println(av)会输出排序后的结果。
如果尝试将一个真正的数组传递给sort.Ints,会发生什么?
package main
import (
"fmt"
"sort"
)
func main() {
var fixedArray = [5]int{1, 5, 2, 3, 7}
fmt.Println("原始数组:", fixedArray)
// sort.Ints(fixedArray) // 编译错误: cannot use fixedArray (type [5]int) as type []int in argument to sort.Ints
// 如果要对数组进行排序,需要先将其转换为切片
sort.Ints(fixedArray[:]) // 将数组转换为切片,然后传递
fmt.Println("排序后的数组 (通过切片操作):", fixedArray)
}编译错误信息(如果直接传递数组):
cannot use fixedArray (type [5]int) as type []int in argument to sort.Ints
这进一步证明了sort.Ints函数严格要求传入一个切片。通过fixedArray[:]这种切片表达式,我们可以将一个数组转换为一个引用该数组全部元素的切片,然后将其传递给sort.Ints。此时,sort.Ints仍然是修改底层数组,因此原数组在函数返回后也会被修改。
理解Go语言中数组和切片的这些核心差异,对于编写高效、正确且符合预期的Go程序至关重要。开发者应根据具体需求,合理选择和使用这两种数据类型。
以上就是深入理解Go语言中的数组与切片:类型、行为与实践的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号