dsfd3546 2018-10-26 13:10
浏览 62
已采纳

使用值接收器附加到具有足够容量的切片

can someone help me understand what happens here?

package main

import (
    "fmt"
)

func appendString(slice []string, newString string) {
    slice = append(slice, newString)
}

func main() {
    slice := make([]string, 0, 1)
    appendString(slice, "a")
    fmt.Println(slice)
}

I know about the slice header and the need to use a pointer receiver. But here, as the underlying array has enough capacity I would expect append to work anyways (just adding the new value to the underlying array and the original [copied] header working as expected)

What is wrong with my assumptions?

  • 写回答

1条回答 默认 最新

  • dousui8263 2018-10-26 13:24
    关注

    Let's add a final print statement to see the result:

    slice := make([]string, 0, 1)
    fmt.Println(cap(slice))
    appendString(slice, "a")
    fmt.Println(slice)
    

    And the output will be (try it on the Go Playground):

    1
    []
    

    Which is correct. One could expect the output to be:

    1
    [a]
    

    The reason why this is not the case is because even though a new backing array will not be allocated, the slice header in the slice variable inside main() is not changed, it will still hold length = 0. Only the slice header stored in the slice local variable inside appendString() (the parameter) is changed, but this variable is independent from main's slice.

    If you were to reslice main's slice, you will see that the backing array does contain the new string:

    slice := make([]string, 0, 1)
    fmt.Println(cap(slice))
    appendString(slice, "a")
    fmt.Println(slice)
    
    slice = slice[:1]
    fmt.Println(slice)
    

    Now output will be (try it on the Go Playground):

    1
    []
    [a]
    

    This is why the builtin append() has to return the new slice: because even if no new backing array is needed, the slice header (which contains the length) will have to be changed (increased) if more than 0 elements are appended.

    This is why appendString() should also return the new slice:

    func appendString(slice []string, newString string) []string {
        slice = append(slice, newString)
        return slice
    }
    

    Or short:

    func appendString(slice []string, newString string) []string {
        return append(slice, newString)
    }
    

    Which you have to reassign where you use it:

    slice := make([]string, 0, 1)
    fmt.Println(cap(slice))
    slice = appendString(slice, "a")
    fmt.Println(slice)
    

    And then you get the expected outcome right away (try it on the Go Playground):

    1
    [a]
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 如何在vue.config.js中读取到public文件夹下window.APP_CONFIG.API_BASE_URL的值
  • ¥50 浦育平台scratch图形化编程
  • ¥20 求这个的原理图 只要原理图
  • ¥15 vue2项目中,如何配置环境,可以在打完包之后修改请求的服务器地址
  • ¥20 微信的店铺小程序如何修改背景图
  • ¥15 UE5.1局部变量对蓝图不可见
  • ¥15 一共有五道问题关于整数幂的运算还有房间号码 还有网络密码的解答?(语言-python)
  • ¥20 sentry如何捕获上传Android ndk 崩溃
  • ¥15 在做logistic回归模型限制性立方条图时候,不能出完整图的困难
  • ¥15 G0系列单片机HAL库中景园gc9307液晶驱动芯片无法使用硬件SPI+DMA驱动,如何解决?