【问题标题】:Is there a difference in behaviour between slice literal and make slice?切片文字和制作切片之间的行为有区别吗?
【发布时间】:2020-12-09 01:54:00
【问题描述】:

注意: Declare slice or make slice? 没有回答我的问题,因为它将切片声明与制作切片进行比较,而我的问题将切片文字与制作切片进行比较。这个问题的答案很简单,因为一个裸切片声明会创建一个 nil 切片,但是,如果您仔细阅读下面的问题,我根本不会创建一个 nil 切片。

有两种方法可以创建切片并附加到切片。我下面的代码以Example 1Example 2 两种方式显示。

package main

import (
    "fmt"
)

func main() {
    // Example 1
    a := []int{}
    fmt.Printf("len(a): %d; cap(a): %d; a: %v\n", len(a), cap(a), a)
    a = append(a, 10, 20, 30, 40, 50)
    fmt.Printf("len(a): %d; cap(a): %d; a: %v\n", len(a), cap(a), a)
    
    // Example 2
    b := make([]int, 0)
    fmt.Printf("len(b): %d; cap(b): %d; b: %v\n", len(b), cap(b), b)
    b = append(b, 10, 20, 30, 40, 50)
    fmt.Printf("len(b): %d; cap(b): %d; b: %v\n", len(b), cap(b), b)
}

输出:

len(a): 0; cap(a): 0; a: []
len(a): 5; cap(a): 6; a: [10 20 30 40 50]
len(b): 0; cap(b): 0; b: []
len(b): 5; cap(b): 6; b: [10 20 30 40 50]

使用[]int{}make([]int, 0) 创建空切片的两种方法是否等效?在任何情况下,他们的行为会有所不同?

【问题讨论】:

  • 链接的问题又链接到相关文档:blog.golang.org/slices-intro。 TL;DR:x := []int{}x := make([]int, 0) 之间没有功能差异。
  • 你是对的。我说错了。 x := []int{}make([]int, 0) 相同。不过,您声称的区别并不存在。
  • @Flimzy x := []int{}make([]int, 0) 相同的事实可以有效回答这个问题。这个事实没有在链接的问题中讨论。发布这个问题的答案并解释两者是相同的不是很好吗?
  • @Volker 在此处查看 Go 规范:golang.org/ref/spec。如果您将其导出为 PDF,您将获得 84 页。它有超过25,000字。我不了解你,但我肯定无法在一小时内阅读 25,000 字的技术文档!
  • 这是一个关于这个主题的好答案:stackoverflow.com/questions/29164375/…

标签: go slice


【解决方案1】:

我稍微修改了你的例子

    // Example 1
    a := []int{}
    pa := &a
  
    // Example 2
    b := make([]int, 0)
    pb := &b

    runtime.KeepAlive(pa)
    runtime.KeepAlive(pb)

编译成:

*** main.go#12   >    a := []int{}
0x4e56a9    488d0538bb1100          lea rax, ptr [runtime.zerobase]
0x4e56b0    4889442470          mov qword ptr [rsp+0x70], rax
0x4e56b5    8400                test byte ptr [rax], al
0x4e56b7    eb00                jmp 0x4e56b9
0x4e56b9    4889842418010000        mov qword ptr [rsp+0x118], rax
0x4e56c1    0f57c0              xorps xmm0, xmm0
0x4e56c4    0f11842420010000        movups xmmword ptr [rsp+0x120], xmm0
*** main.go#13   >    pa := &a
0x4e56cc    488d842418010000        lea rax, ptr [rsp+0x118]
0x4e56d4    4889442460          mov qword ptr [rsp+0x60], rax
*** main.go#16   >    b := make([]int, 0)
0x4e56d9    488d0520020100          lea rax, ptr [__image_base__+1005824]
0x4e56e0    48890424            mov qword ptr [rsp], rax
0x4e56e4    0f57c0              xorps xmm0, xmm0
0x4e56e7    0f11442408          movups xmmword ptr [rsp+0x8], xmm0
0x4e56ec    e8bf49f6ff          call $runtime.makeslice
0x4e56f1    488b442418          mov rax, qword ptr [rsp+0x18]
0x4e56f6    4889842400010000        mov qword ptr [rsp+0x100], rax
0x4e56fe    0f57c0              xorps xmm0, xmm0
0x4e5701    0f11842408010000        movups xmmword ptr [rsp+0x108], xmm0
*** main.go#17   >    pb := &b
0x4e5709    488d842400010000        lea rax, ptr [rsp+0x100]
0x4e5711    4889442458          mov qword ptr [rsp+0x58], rax

似乎make([]int, 0) 导致堆分配(通过$runtime.makeslice())但没有 - 深入到sources 表明makeslice() 也返回基于&zerobase 的切片:

    if size == 0 {
        return unsafe.Pointer(&zerobase)
    }

因此,两个 sn-ps 都给出相同的切片结构,其中数据指针设置为 zerobase

【讨论】:

  • 它们在语义上是等价的。您的示例中转义分析不同的事实不能保证是一致的,并且在语言规范中没有依据。
  • @JimB 发现案例在分配方面是等效的,我编辑了答案。
  • @maxim_ge 感谢您的详细回答。这很好地回答了我的问题。我可以建议您编辑答案以删除您之前得出的错误结论并只写正确的结论。这将使您的答案更清晰、更易于阅读。
猜你喜欢
  • 2017-05-29
  • 2014-07-25
  • 1970-01-01
  • 1970-01-01
  • 2020-07-23
  • 1970-01-01
  • 2014-06-19
  • 2014-08-07
  • 2015-08-27
相关资源
最近更新 更多