在GoLang中,slice2:= slice1是否等于slice2:= slice1 [:]?

Ste*_*una 3 go slice

以下两行代码是否在GoLang中执行相同的操作?我想要做的是将一个切片复制到另一个切片:

slice1 := make([]int, 5)
slice2 := slice1 #line1
slice2 := slice1[:] #line2
Run Code Online (Sandbox Code Playgroud)

我运行此代码来测试行为,但显然它们都以相同的方式工作:

func main() {
    s1 := make([]int, 5, 5)
    s1[2] = 33
    fmt.Printf("s1: %v: address of slice %p\n", s1, &s1)
    s2 := s1[:]
    s2[1] = 5
    fmt.Printf("s2: %v: address of slice %p\n", s2, &s2)
    s3 := s1
    s3[0] = 23
    fmt.Printf("s3: %v: address of slice %p\n",s3, &s3)
    fmt.Printf("s2: %v: address of slice %p\n", s2, &s2)
    fmt.Printf("s1: %v: address of slice %p\n", s1, &s1)
}
Run Code Online (Sandbox Code Playgroud)

输出是:

s1: [0 0 33 0 0]: address of slice 0x40c0e0
s2: [0 5 33 0 0]: address of slice 0x40c100
s3: [23 5 33 0 0]: address of slice 0x40c120
s2: [23 5 33 0 0]: address of slice 0x40c100
s1: [23 5 33 0 0]: address of slice 0x40c0e0
Run Code Online (Sandbox Code Playgroud)

因此,片段(s1,s2,s3)的内存地址不同,但指向包含在其中的数组的指针指向相同的内存地址.

我想知道这两种方式之间是否存在某些变化,或者是否有某种惯例表明哪种方式更好用.

icz*_*cza 5

结果是一样的.

你没有检查的一件事是容量,切片的另一个属性.那么我们来检查一下:

s := make([]int, 2, 4)
s2 := s
s3 := s[:]

fmt.Println(len(s), cap(s))
fmt.Println(len(s2), cap(s2))
fmt.Println(len(s3), cap(s3))
Run Code Online (Sandbox Code Playgroud)

输出(在Go Playground上试试):

2 4
2 4
2 4
Run Code Online (Sandbox Code Playgroud)

基本上,切片表达 s[:]意味着切片,并使用0作为较低的索引,并len(s)使用上部和cap(s)容量.所以结果将是一个相同的切片s.

为了便于阅读,只需复制切片标题:s2 := s.

另请注意,如果s是这样nil,复制它和切片它也会导致nil切片:

var s []int
s2 := s
s3 := s[:]

fmt.Println(len(s), cap(s), s == nil)
fmt.Println(len(s2), cap(s2), s2 == nil)
fmt.Println(len(s3), cap(s3), s3 == nil)
Run Code Online (Sandbox Code Playgroud)

以上输出是(在Go Playground上试试):

0 0 true
0 0 true
0 0 true
Run Code Online (Sandbox Code Playgroud)

所以结果完全没有区别.s2 := s编写时s2 := s[:],编译器实现可能会或可能不会模仿语句,因此后者可能会更慢.但同样,没有理由不简单地复制它.