slice和数组的区别:
相同点:下标取值,适用于range,可调用len(),cap(),形式相同。
不同点:声明方式不同;slice能用append插入元素,数组不行;slice可由make创建;内部实现有差异
- 创建或声明方式
// 数组在创建时,需指定最大存放的元素个数
var array = [5]int{1, 2, 3, 4, 5}
var array = [5]int{}
var slice = []int{1, 2, 3, 4, 5} // 创建cap=5,len=5,并初始化的slice
var slice = make([]int, 0, 5) //创建cap=5,len=0的slice
var slice = make([]int, 5) // 创建cap=5,len=5的slice
- 扩容性
var slice = make([]int, 3,5)
slice = append(slice, 1)
// 当slice的cap不够时,将自动扩容,扩容后的slice可能与原来的slice地址不一样。
// 扩容的比率,由开始的近2倍,变为后来的1.25倍
- 作为参数时的传递方式
在go中,所有的参数传递都是以值传递的方式,所以数组和切片都是值传递方式。但是由于切片其内在的实现,表现出来有如引用传递的假象,就像C++中的共享指针一样。另外map,channel也是类似特性。
func PassSlice(s []int) {
s[0] = 10
}
func PassArray(a [3]int) {
a[0] = 10
}
func Test_Para(t *testing.T) {
s := []int{1, 2, 3}
a := [3]int{1, 2, 3}
fmt.Println("s: ", s)
fmt.Println("a: ", a)
PassSlice(s)
PassArray(a)
fmt.Println("s: ", s)
fmt.Println("a: ", a)
}
输出:
s: [1 2 3]
a: [1 2 3]
s: [10 2 3]
a: [1 2 3]
这里的slice看起来像个引用传递,原因是,在slice的结构内部有一个指向底层数组的指针,slice的下标取值,通过类似C语言指针取值的方式,实际操作底层数组。