c语言编程笔录

首页 >   > 笔记大全

笔记大全

Go语言数组和切片的区别有哪些

更新时间:2023-10-25

前言:

在Go语言中,数组和切片是常见的数据结构,用于存储一系列元素。虽然它们都可以用于存储多个元素,但在内部实现和使用方式上有一些区别。本文将从多个方面对Go语言中的数组和切片进行比较,以便更好地理解它们之间的区别。

1. 内存分配和长度限制

数组在创建时,内存会连续分配。而切片在创建时,内部会有一个动态数组,其长度和容量是可以动态变化的。这也是为什么切片具有可变长度,而数组长度固定的原因。

// 创建固定长度的数组
var arr [5]int

// 创建切片,内部有动态数组
var s []int

另一个区别是数组的长度是类型的一部分,即不同长度的数组是不可互相赋值的。而切片的长度并不固定,所以可以互相赋值。

2. 传递方式

当数组作为函数参数传递时,会进行一次值拷贝。这意味着在函数中修改数组的元素并不能反映到原始数组上。而切片是引用类型,当切片作为函数参数传递时,传递的是切片的引用,所以在函数中修改切片的元素会影响到原始切片。

func modifyArray(arr [5]int) {
    arr[0] = 10
    fmt.Println(arr) // [10 2 3 4 5]
}

func modifySlice(s []int) {
    s[0] = 10
    fmt.Println(s) // [10 2 3 4 5]
}

func main() {
    arr := [5]int{1, 2, 3, 4, 5}
    s := arr[:]

    modifyArray(arr)
    fmt.Println(arr) // [1 2 3 4 5]

    modifySlice(s)
    fmt.Println(s) // [10 2 3 4 5]
}

在上面的示例中,修改数组的函数`modifyArray`并不能改变原始数组`arr`的内容,而修改切片的函数`modifySlice`会改变原始切片`s`的内容。

3. 动态增长

由于切片具有可变长度,当切片的容量不足以容纳更多元素时,切片会自动扩容。在扩容过程中,会新建一个更大的底层数组,并将原有数组中的元素拷贝到新数组中。这是因为切片内部维护了一个指向底层数组的指针,所以扩容操作并不会影响到外部使用切片的其他地方。

s := []int{1, 2, 3, 4, 5}
fmt.Println(len(s), cap(s)) // 5, 5

s = append(s, 6)
fmt.Println(len(s), cap(s)) // 6, 10

在上面的示例中,切片`s`的容量不足以容纳新的元素,所以在执行`append`操作时,会自动扩容切片。由于底层数组长度不够,会重新创建一个长度为10的新数组,并将原来的元素拷贝到新数组中。

总结:

数组和切片都是在Go语言中用于存储一系列元素的数据结构,但它们在内部实现和使用方式上有一些区别。数组在创建时内存连续分配,长度固定,传递方式为值拷贝;切片在创建时内部有一个动态数组,长度可变,传递方式为引用传递。切片具有动态增长的特性,可以自动扩容,而数组的长度是固定的。

根据实际需求选择数组还是切片,可以更好地发挥Go语言的特性。如果需要固定长度且传递行为为值拷贝,可以使用数组;如果需要可变长度且传递行为为引用传递,可以使用切片。