go - slice 文字和make slice之间在行为上有区别吗?

标签 go slice

注意: Declare slice or make slice?不能回答我的问题,因为它比较 slice 声明与make slice,而我的问题比较 slice 文字与make slice。该问题的答案很简单,因为裸 slice 声明会创建一个nil slice ,但是,如果您仔细阅读下面的问题,我根本不会创建nil slice 。
有两种方法可以创建 slice 并将其附加到 slice 。我的以下代码将两种方式分别显示为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)创建空 slice 的两种方法是否等效?他们在任何情况下都会改变行为吗?

最佳答案

我修改了您的示例

    // 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的 slice :
    if size == 0 {
        return unsafe.Pointer(&zerobase)
    }
因此,这两个片段都提供了相同的 slice 结构,其中数据指针设置为zerobase

关于go - slice 文字和make slice之间在行为上有区别吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63493026/

相关文章:

arrays - 在numpy中获取3D数组的2D切片的平均值

go - 在 Golang 中将接口(interface){}转换为结构

go - 我们可以限制一次从goroutine一次调用函数吗

postgresql - 转换参数 $1 类型 : unsupported type []interface {}, 的一个接口(interface)

arrays - 使用 struct 在 Go 中处理空 JSON 数组

Javascript - 多个不等随机数生成器

javascript - 使用多个嵌套分隔符拆分字符串

go - 无需接口(interface)即可将多种类型合二为一

go - Gin-Gonic 中间件声明

struct - 如何在 slice 内设置结构的字段?