Go 语言数组和切片的区别详解:从结构到函数传参
Go 语言中的数组和切片虽然看起来相似,但在内存管理和函数参数传递上有着本质的差异。文章详细拆解了数组固定长度的特性以及切片基于动态扩容的实现原理,重点分析了函数传参时的拷贝与引用机制。
准备条件
在进行 Go 语言的数组与切片操作前,需要理解两者的基本定义。数组是同一种数据类型元素的集合,而切片则是基于数组封装的可变长度序列。掌握它们的声明语法是区分二者表现的基础。
数组的核心特性
在 Go 语言中,数组的大小是其类型的一部分。[4]int 和 [5]int 是完全不同且互不兼容的类型。这使得数组的使用场景相对有限,因为一旦创建,其大小即无法改变。
数组元素通过从零开始的索引访问:
第1步:数组的声明与初始化
目的:了解如何正确声明和初始化定长容器。
操作:可使用默认零值声明、逐一赋值或使用 ... 省略号推导长度。
func main() {
var nums [3]int // 声明并初始化为默认零值
var nums1 = [4]int{1, 2, 3, 4} // 声明同时初始化
var nums2 = [...]int{1, 2, 3, 4, 5} // ...可以表示后面初始化值的长度
fmt.Println(nums) // [0 0 0]
fmt.Println(nums1) // [1 2 3 4]
fmt.Println(nums2) // [1 2 3 4 5]
}
第2步:将数组作为函数参数传递
结果:** 数组作为参数传递时,实际上是传递了一份副本。这意味着在函数内部修改数组元素,不会影响到原始数组。
package main
import (
"fmt"
)
func Add(numbers [5]int) {
for i := 0; i < len(numbers); i++ {
numbers[i] = numbers[i] + 1
}
fmt.Println("numbers in Add:", numbers) // [2 3 4 5 6]
}
func main() {
// declare and initialize the array
var numbers [5]int
for i := 0; i < len(numbers); i++ {
numbers[i] = i + 1
}
Add(numbers)
fmt.Println("numbers in main:", numbers) // [1 2 3 4 5]
}
切片的结构与优势
切片(Slice)是更加常用的数据结构,它支持自动扩容,是基于底层数组的一层封装。切片包含三个关键属性:指针(指向底层数组)、长度(当前可用元素数)和容量(从起点到底层数组末尾的距离)。
底层源码定义如下:
type slice struct {
array unsafe.Pointer
len int
cap int
}
第3步:切片的声明与管理
参数要点:** make 函数可用于构造具有特定长度和容量的切片。
func main() {
var nums []int // 声明切片
fmt.Println(len(nums), cap(nums)) // 0 0
nums = append(nums, 1) // 初始化
fmt.Println(len(nums), cap(nums)) // 1 1
nums1 := []int{1,2,3,4} // 声明并初始化
fmt.Println(len(nums1), cap(nums1)) // 4 4
nums2 := make([]int,3,5) // 使用make()函数构造切片
fmt.Println(len(nums2), cap(nums2)) // 3 5
}
第4步:将切片作为函数参数传递
完成判断:** 当切片作为参数时,由于传递的是对底层数组的引用,函数内的修改会直接反映到调用者的切片上。
package main
import (
"fmt"
)
func Add(numbers []int) {
for i := 0; i < len(numbers); i++ {
numbers[i] = numbers[i] + 1
}
fmt.Println("numbers in Add:", numbers) // [2 3 4 5 6]
}
func main() {
var numbers []int
for i := 0; i < 5; i++ {
numbers = append(numbers, i+1)
}
Add(numbers)
fmt.Println("numbers in main:", numbers) // [2 3 4 5 6]
}
总结
- 长度与空间:** 数组长度固定,不可动态增加;切片长度可变,支持动态扩容。
- 内存分配:** 数组在定义时即确定大小并分配空间;切片在运行时根据需求动态分配。
- 传参行为:** 传递数组会进行全盘拷贝,不影响原件;传递切片通过引用影响底层数组,具有副作用。
- 属性差异:** 切片额外具备容量(Capacity)这一概念,用于管理内存预分配效率。
以上就是 Go 语言数组和切片的区别详解的详细内容,更多关于 Go 语言基础操作技巧的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













