使用 s[2:4] 进行切片截取的时候,底层并不会发生数组的拷贝,而是直接引用原数组中的地址,即 s[2:4]s 指向的是同一个底层数组。

官方背书

Slicing does not copy the slice’s data. It creates a new slice value that points to the original array. This makes slice operations as efficient as manipulating array indices. Therefore, modifying the elements (not the slice itself) of a re-slice modifies the elements of the original slice

切片操作不会复制切片的数据。它会创建一个指向原始数组的新切片值。这使得切片操作与操作数组索引一样高效。因此,修改重新切片的元素 (而不是切片本身)会修改原始切片的元素

简单验证

如官网所说,修改重新切片的元素(而不是切片本身)会修改原始切片的元素。那我们只要修改重新切片的元素,然后打印原始切片,看看是否也会被修改。

package main
 
import "fmt"
 
func main() {
	s := make([]int, 5)
 
	// slicing
	t := s[2:4]
	// modify
	t[0], t[1] = 1, 2
 
	// print
	fmt.Printf("s: %v\n", s)
}
 
----
s: [0 0 1 2 0]

底层验证

让我们尝试用 unsafe 包来获取两个切片的底层数组地址,看看是否指向同一个地址。

package main
 
import (
	"fmt"
	"unsafe"
)
 
func main() {
	s := make([]int, 5)
	array := unsafe.SliceData(s)
	pointer := unsafe.Pointer(array)
	for i := 0; i < 5; i++ {
		pointer = unsafe.Add(pointer, unsafe.Sizeof(int(0)))
		fmt.Printf("&s[%d]: %v\n", i, pointer)
	}
 
	// slicing
	t := s[2:4]
	array = unsafe.SliceData(t)
	pointer = unsafe.Pointer(array)
	for i := 0; i < 2; i++ {
		pointer = unsafe.Add(pointer, unsafe.Sizeof(int(0)))
		fmt.Printf("&t[%d]: %v\n", i, pointer)
	}
}
&s[0]: 0x140000b4038
&s[1]: 0x140000b4040
&s[2]: 0x140000b4048
&s[3]: 0x140000b4050
&s[4]: 0x140000b4058
&t[0]: 0x140000b4048
&t[1]: 0x140000b4050