golang中常用的slice,在使用的过程中很容易用错,总结下来根本原因是没有了解其底层数据结构。
1. 数据结构样式
// 这里只是举例
type slice struct {
pointer *interface{} // 指向值数组的指针
length int64 // 当前有效值长度
capacity int64 // 当前数组总长度
}
// PS:
1. capacity >= length
2. 扩容规则 capacity *= 2
3. append操作时,如slice = append(slice, 1)
if length <= append {
// slice的地址没有改变,只是在底层的数据有效值位置后插入对应的值,并更改结构体中length的值
length++
pointer[length] = 1
}
else {
capacity *= 2
tempPoint = malloc(capacity * sizeof(值类型)) // 扩容
copy(temPoint, pointer)
pointer = temPoint
pointer = append(temPoint, 1)
}
2. 案例
func sliceTest1(value []int) {
value[0] = 100
}
func sliceTest2(value []int) []int {
value = append(value, 1)
return value
}
func main() {
sliceValue := make([]int, 1)
fmt.Println(sliceValue) // 1
sliceTest1(sliceValue)
fmt.Println(sliceValue) // 100
sliceValue2 := sliceTest2(sliceValue)
fmt.Println(sliceValue) // 100
fmt.Println(sliceValue2) // 100 1
}
3. 案例分析
- slice在函数传参时是值传递
- 因为结构中的指针地址的值也相同,所以在更改原有的值时,也会起到作用,如sliceTest1方法
- 但当长度(slice中的length和capacity)发生变化时,并不会影响到原始的slice,所以在调用sliceTest2方法后,sliceValue的值仍没有变化
4. 小结
1. slice在函数参数传递时时值传递,在没有length变化的情况下,会启动引用传递的效果,否则就不会影响到原有变量的值。
2. 想要放心大胆的使用slice,建议在函数传参时,传入*slice,使用是如(*sliceValue)即可,这样就可以真正的引用传递。
PS:
如有错漏,还望指出,教学相长,共同进步。