当前位置: 首页 > 知识库问答 >
问题:

切片文字和制作切片在行为上有区别吗?

邓欣可
2023-03-14

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

有两种方法可以创建切片并追加到它。下面的代码以示例1示例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)创建空切片的两种方法是否等效?在任何情况下,他们的行为会有所不同吗?

共有1个答案

窦伟
2023-03-14

我稍微修改了你的例子

    // 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()),但没有深入到源显示makeslice()也返回

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

因此,这两个片段给出了相同的切片结构,其中数据指针设置为zerobase

 类似资料:
  • 问题内容: 在Golang中,和之间有什么区别? 我发现这两种方法都可行,但是哪一种更好? 问题答案: 除了fabriziom的答案外,您还可以在“转到切片:用法和内部方法”中看到更多示例,其中提到了的用法: 由于slice()的零值就像 零长度的slice一样 ,您可以声明slice变量,然后在循环中附加到该变量: 这意味着,要附加到切片,您不必先分配内存:切片足以作为要添加的切片。

  • 问题内容: 我很好奇拆包切片并将其作为参数发送给可变参数函数。 假设我们有一个带有可变参数的函数: 如果我们不想传入一个接口,它就可以工作,那么我们是否拆包都没关系: 如果我们有一片片的话,那会很棘手。在这里,编译器不允许我们传递解压版本: 错误提示: 在解包参数中不能将sliceOfSlices(类型[] [] interface {})用作类型[] interface {} 我不知道为什么会这

  • 问题内容: 我有以下代码: 但是我想将一个指向字节切片的指针传递给另一个函数,并在那里切片,所以类似: 它给我一个错误,我不能在函数参数中使用type 作为类型,并且不能对type进行切片。怎么了?默认情况下切片不是通过引用传递的吗?我试图在没有指针的情况下执行此操作,但是它不起作用- 正在复制数组。我怎样才能做到这一点? 问题答案: 该错误来自您尚未发布的拼写错误(您尝试传递一个切片而不是指向的

  • 问题内容: 我有一本字典,想将其一部分传递给函数,该部分由键列表(或元组)给出。像这样: 现在,理想情况下,我希望能够做到这一点: …但这不起作用,因为它将查找名为的键。而且甚至不是有效的Python(尽管看起来很方便)。 我知道我可以这样做: 或这个: 这更紧凑…但是我觉得必须有一种“更好”的方式来做到这一点。我想念一个更优雅的解决方案吗? (我正在使用Python 2.7) 问题答案: 您应该

  • 问题内容: 转到“切片”问题,请检查以下内容,并在我遗漏某些东西时发表评论。 输出: 以上是合理的。 输出: 这是否也应该使数组摆脱s = s [:2]的恐慌? 问题答案: Go中的Subslicing可让您在切片末尾进行切片,只要它仍在底层阵列的容量范围内即可。您不能 在 该切片的开始 之前 进行切片,但是只要不超过最后分配的索引,就可以在该切片之后进行切片。 例如,然后工作,但随后会出现恐慌,

  • 问题内容: 我想知道我什么时候做类似的事情 创建新字符串或返回视图/迭代器 问题答案: Python会进行逐个切片,这意味着每次切片时(非常琐碎的切片(例如)除外),它都会将所有数据复制到一个新的字符串对象中。 根据一位开发人员的说法,之所以做出此选择是因为 [按引用切片]方法更复杂,更难实现并且可能导致意外行为。 例如: 使用“按切片复制”设计,可以立即释放字符串。尽管您只对第一个字符感兴趣,但