Go 数组是值类型,赋值和函数传参操作都会复制整个数组数据。
切片slice是引用传递,不需要额外的内存,而切片本身是一种数组指针的封装。
下面是一个数组传参测试输出:
func Test1() {
array1 := [2]int{100, 200}
array2 := array1
fmt.Printf("array1: %p, %v
", &array1, array1)
fmt.Printf("array2: %p, %v
", &array2, array2)
printArray(array1)
}
func printArray(x [2]int) {
fmt.Printf("func array: %p, %v
", &x, x)
}
array1: 0xc000271590, [100 200]
array2: 0xc0002715a0, [100 200]
func array: 0xc0002715d0, [100 200]
假想每次传参都用数组,那么每次数组都要被复制一遍。这样会消耗掉大量的内存。于是乎有人想到,函数传参用数组的指针。
但是传递数组指针会有一个弊端,万一原数组的指针指向更改了,那么函数里面的指针指向都会跟着更改。
所以说把第一个大数组传递给函数会消耗很多内存,采用切片的方式传参可以避免上述问题。切片是引用传递,所以它们不需要使用额外的内存并且比使用数组更有效率。
当然也有特例,借用一个
package main
import "testing"
func array() [1024]int {
var x [1024]int
for i := 0; i < len(x); i++ {
x[i] = i
}
return x
}
func slice() []int {
x := make([]int, 1024)
for i := 0; i < len(x); i++ {
x[i] = i
}
return x
}
func BenchmarkArray(b *testing.B) {
for i := 0; i < b.N; i++ {
array()
}
}
func BenchmarkSlice(b *testing.B) {
for i := 0; i < b.N; i++ {
slice()
}
}
func git:(main) go test -bench . -benchmem -gcflags "-N -l"
goos: darwin
goarch: amd64
pkg: func
cpu: Intel(R) Core(TM) i5-5257U CPU @ 2.70GHz
BenchmarkArray-4 339076 3028 ns/op 0 B/op 0 allocs/op
BenchmarkSlice-4 281892 4295 ns/op 8192 B/op 1 allocs/op
PASS
ok func 4.364s
这样对比看来,并非所有时候都适合用切片代替数组,因为切片底层数组可能会在堆上分配内存,而且小数组在栈上拷贝的消耗也未必比make 消耗大。
页面更新:2024-03-08
本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828
© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号