Golang的append()什么时候创建一个新的切片?

2023-11-26

根据内置 API 文档,append()会在原切片容量不够大时重新分配并复制到新的数组块中。

这是一个用于创建字母表(在本例中为布尔值)组合的递归算法(简化版本)。字母表的成员(true、false)被递归地添加到切片中,直到达到正确的长度,此时它会通过通道发送。

package main

import (
    "fmt"
)

func AddOption(c chan []bool, combo []bool, length int) {
    if length == 0 {
        fmt.Println(combo, "!")
        c <- combo
        return
    }
    var newCombo []bool
    for _, ch := range []bool{true, false} {
        newCombo = append(combo, ch)
        AddOption(c, newCombo, length-1)
    }
}

func main() {
    c := make(chan []bool)
    go func(c chan []bool) {
        defer close(c)
        AddOption(c, []bool{}, 4)
    }(c)
    for combination := range c {
        fmt.Println(combination)
    }
}

Here是此代码的游乐场链接。在输出中:

[true true true true] !
[true true true false] !
[true true true false]
[true true true false]
[true true false true] !
[true true false false] !
[true true false false]
[true true false false]
[true false true true] !
[true false true false] !
[true false true false]
[true false true false]
[true false false true] !
[true false false false] !
[true false false false]
[true false false false]
[false true true true] !
[false true true false] !
[false true true false]
[false true true false]
[false true false true] !
[false true false false] !
[false true false false]
[false true false false]
[false false true true] !
[false false true false] !
[false false true false]
[false false true false]
[false false false true] !
[false false false false] !
[false false false false]
[false false false false]

以感叹号结尾的行是从 AddOption 发送到通道的行。那些没有的内容出现在另一边(即在 main() 中)。很明显,通过通道发送的切片在发送后发生了变化。

由于 AddOption 在发送切片后立即返回,因此修改必须来自代码块

var newCombo []bool
for _, ch := range []bool{true, false} {
    newCombo = append(combo, ch)
    AddOption(c, newCombo, length-1)
}

但是,根据文档,append() 应该返回一个新切片(cap(combo) 不够大)。根据这个答案,发送给AddOption的切片描述符应该是一个副本;这不是真的吗?据我所知,作为 AddOption() 的第二个参数发送的值要么是指向切片描述符的指针,要么append() 不返回新切片。


您将切片(数据类型)与实际表示混淆了。切片描述符由一对 int 组成,一个代表 len,一个代表 cap,以及一个指向底层数据的指针。

因此,append 返回的确实是一个新切片,传递给 add 选项的确实是切片描述符的副本。但由于描述符有一个指向数据的指针,因此指针值(底层数据的地址)是相同的。

EDIT:这是一个代码片段来说明我的观点:

package main

import "fmt"

func main() {
    s := make([]int, 0, 5)
    s = append(s, []int{1, 2, 3, 4}...)

    a := append(s, 5)
    fmt.Println(a)

    b := append(s, 6)
    fmt.Println(b)
    fmt.Println(a)
}

If you run this, 你得到:

[1 2 3 4 5]
[1 2 3 4 6]
[1 2 3 4 6]

因为自从s仍然有能力,两者a and b共享相同的数据指针。如果将容量更改为 4,则会打印:

[1 2 3 4 5]
[1 2 3 4 6]
[1 2 3 4 5]
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Golang的append()什么时候创建一个新的切片? 的相关文章

随机推荐

  • 如何使用 Android 数据绑定动态更改视图可见性

    我正在尝试使用数据绑定实现一种简单的视图隐藏 显示 我有一个 api 调用 并且在 api 调用正在进行时我必须显示一个进度条 一旦我收到响应 就必须忽略此进度并显示数据 我尝试使用数据绑定动态更改进度条的可见性 但什么也没发生 仅在第一次
  • Python - 使用 pytest 跳过测试,除非指定

    背景 我正在使用 pytest 来测试将数据推送到数据库的网络抓取工具 该类仅拉取 html 并将 html 推送到数据库以供稍后解析 我的大多数测试都使用虚拟数据来表示 html Question 我想做一个测试 从网站上抓取网页 但我希
  • Jaxb 生成的 xml - 根元素前缀问题

    我正在尝试使用 jaxb 生成 xml 我创建了 xsd 并生成了 java 类 但是当我生成 xml 时 我在根标记中添加前缀 ns2 这是我不想要的 例如 我希望根标签是
  • 如何使SurfaceView具有透明背景?

    我有简单的布局
  • SQLAlchemy 不会更新我的数据库

    我正在使用 SQLAlchemy 0 7 8 制作金字塔应用程序 我使用的是64位Python3 2 问题是 为什么以下函数不向数据库提交任何内容 def create card sText sCard create a wildcard
  • Objectify 和 TimerTask:没有为此线程注册 API 环境

    我想得到一个TimerTask设置为定期从 Google App Engine 数据存储中删除条目 我是否设置了一个ServletContextListener with a Timer 在 的里面contextInitialized 我已
  • 涉及 Enum 的多重继承元类冲突

    我需要一个枚举类的双重继承 但也支持我自己的方法 这是上下文 import abc from enum import Enum class MyFirstClass abc ABC abc abstractmethod def func s
  • 如何在 DENO 中使用 npm 模块?

    德诺超级酷 我早上看到了 现在想迁移到 deno 我试图将现有的 Nodejs 脚本移至 deno 任何人都可以帮助我如何在 deno 中使用 npm 模块 我需要 esprima 模块 这个有包https github com denol
  • 通过 jquery.couch.js 或其他方式在 Couchapp/CouchDB 中进行用户注册

    背景 现在 我正在尝试使用 couchDB couchapp 构建一个应用程序 该应用程序将存储来自用户的持久且重要的信息 并且停留在用户使用 couchapp 注册所需的步骤上 本质上 我想做的是有一个简单的注册表单 用户可以使用它来注册
  • 如何与 PHP 设置 WebSocket 安全连接?

    我找不到任何有关在 PHP 中设置 wss 连接的信息 我连接抛出ws没有问题 顺便说一句 我正在使用这个非常棒的库来做到这一点 https github com albeva php websocket 但我的网站使用 https 我需要
  • 设置RadioButton的value属性

    我需要根据从数据库返回的数据构建一个单选按钮列表 每个按钮都需要有一个与之关联的值 我可以根据所选按钮获取该值 理想情况下我只会使用RadioButtonList控件 但是 我需要一个非常自定义的布局RadioButtonList似乎无法处
  • 使用 Avaudioengine iOS 的低通滤波器 + 采样率转换

    我们正在开发一个项目 该项目允许我们使用一些低通滤波器和高通滤波器以 5k Hz 采样率从麦克风录制一些声音 我们正在使用什么 我们正在使用音频引擎以此目的 我们正在使用AVA音频转换器用于降低采样率 我们正在使用AVAudioUnitEQ
  • JavaScript 对象的动态深度选择

    对于单个属性 这相当简单 var jsonobj test ok var propname test Will alert ok alert jsonobj propname 但我想做的是使用嵌套属性 var jsonobj test te
  • sqlite3-ruby 无法在 rvm 1.8.7 上运行

    从 RVM 1 8 7 开始升级到 Rails 3 操作系统 10 5 8 Output josh crewss macbook joshcrews gem install sqlite3 rubyBuilding native exten
  • scrapy 蜘蛛中的多重继承

    是否可以创建一个继承两个基本蜘蛛 即 SitemapSpider 和 CrawlSpider 功能的蜘蛛 我一直在尝试从各个网站抓取数据 并意识到并非所有网站都列出了网站上的每个页面 因此需要使用 CrawlSpider 但 CrawlSp
  • 为什么浏览器不支持gRPC?

    gRPC 基于 HTTP 2 假设 得到浏览器的广泛支持 因此 我觉得从浏览器使用gRPC应该没有问题 然而 很明显有一个问题 协议 grpc web 是不同的 因为 由于浏览器限制 而存在 还有大量博客文章描述了为让 gRPC 在浏览器中
  • 为什么在分配给变量(别名条件)时,类属性的类型缩小检查不起作用?

    如何缩小别名条件表达式中类的属性类型 Short 在类方法中 我想进行类型缩小检查 例如this end null this head null 但我想首先将此检查的结果分配给一个变量 然后再在类型缩小中使用它if条款 它没有按预期工作 不
  • 您可以将 WebApi 2 基于属性的路由与 WebForms 一起使用吗?

    正如标题所述 我想知道是否可以将 WebAPI 2 的基于属性的路由与 WebForms 一起使用 我觉得这显然可以完成 因为您可以在 WebForms 应用程序中很好地使用 WebAPI2 我只是不知道如何启用基于属性的路由 基于此art
  • PowerShell:将 16MB CSV 导入 PowerShell 变量会创建 >600MB 的 PowerShell 内存使用量

    我试图理解为什么当我导入一个大约 16MB 的文件作为变量时 PowerShell 的内存膨胀如此之大 我可以理解该变量周围有额外的内存结构 但我只是想理解为什么它那么高 这就是我在下面所做的 只是任何人都可以运行的另一个脚本的精简简单片段
  • Golang的append()什么时候创建一个新的切片?

    根据内置 API 文档 append 会在原切片容量不够大时重新分配并复制到新的数组块中 这是一个用于创建字母表 在本例中为布尔值 组合的递归算法 简化版本 字母表的成员 true false 被递归地添加到切片中 直到达到正确的长度 此时