Golang面试题切片Slice和数组比较
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 消耗大。