当切片基于数组切片得到时,切片底层数组首地址是否在原数组范围内,见如下代码:
package main
import "fmt"
func main() {
a := [...]int{1, 2, 3}
s := a[:2] // [low:high]
fmt.Println(&a[0], a, &s[0], s, len(s), cap(s)) // 0xc0000bc000 [1 2 3] 0xc0000bc000 [1 2] 2 3
// 此时切片占用地址范围包含在原始数组范围中,所以切片指针指向数组首地址,长度等于high-low,容量等于得到的切片的底层数组的容量-low
// 给切片追加一个元素
s = append(s, 5)
fmt.Println(&a[0], a, &s[0], s, len(s), cap(s)) // 0xc0000bc000 [1 2 5] 0xc0000bc000 [1 2 5] 2 3
// 此时切片占用地址范围仍然包含在原始数组范围中,所以切片指针还是指向数组首地址,但将数组元素a[2]改为了5
// 给切片再追加一个元素
s = append(s, 6)
fmt.Println(&a[0], a, &s[0], s, len(s), cap(s)) // 0xc0000bc000 [1 2 5] 0xc0000b2060 [1 2 5 6] 4 6
// 此时切片占用地址范围已超出原始数组范围,所以切片进行了一次内存申请,并将数据copy到新地址中,同时capacity也增加了
}
总结:当切片占用地址范围未超出原始数组范围时,切片首地址在原始数组地址范围内;否则将重新申请额外内存,不再与原始数组共用内存。