【slice】注意事项

实验一:
我们都知道,数组声明以后,数组的地址和数组内元素的地址是固定的。
而slice则不然,如果修改slice1的元素的值,而不进行append操作,那么slice1[0]的地址会改变吗?

【slice】注意事项_第1张图片
image.png

【slice】注意事项_第2张图片
image.png

也就是说,修改slice的元素的值,元素的地址不变。那么,我们来看看append函数到底干了什么事儿。首先追溯append()函数,然而在builtin.go中,只有

// The append built-in function appends elements to the end of a slice. If
// it has sufficient capacity, the destination is resliced to accommodate the
// new elements. If it does not, a new underlying array will be allocated.
// Append returns the updated slice. It is therefore necessary to store the
// result of append, often in the variable holding the slice itself:
//  slice = append(slice, elem1, elem2)
//  slice = append(slice, anotherSlice...)
// As a special case, it is legal to append a string to a byte slice, like this:
//  slice = append([]byte("hello "), "world"...)
func append(slice []Type, elems ...Type) []Type

代码追溯看不到实现,在调试运行中,发现跳转到src\runtime\slice.go的growslice函数,打开src\runtime\slice.go,

type slice struct {
    array unsafe.Pointer
    len   int
    cap   int
}
//略...
func growslice(et *_type, old slice, cap int) slice {
//略...
    newcap := old.cap
    doublecap := newcap + newcap
    if cap > doublecap {
        newcap = cap
    } else {
        if old.len < 1024 {
            newcap = doublecap
        } else {
            for newcap < cap {
                newcap += newcap / 4
            }
        }
    }
//略...
    var p unsafe.Pointer
//略...
    return slice{p, old.len, newcap}
}

由此可见,在growslice中,是声明并且初始化了一个新的slice结构体,并且赋值了一个新的unsafe.Pointer地址,原来slice的长度和一个新的容量newcap,所以地址必然改变!

你可能感兴趣的:(【slice】注意事项)