go - Reader接口(interface)改变值

标签 go slice reader

我有一个关于阅读器界面的问题,定义如下:

type Reader interface {
    Read(p []byte) (n int, err error)
}

我有以下使用阅读器界面的代码:

package main

import (
    "fmt"
    "os"
)

// Reading files requires checking most calls for errors.
// This helper will streamline our error checks below.
func check(e error) {
    if e != nil {
        panic(e)
    }
}

func main() {

    // You'll often want more control over how and what
    // parts of a file are read. For these tasks, start
    // by `Open`ing a file to obtain an `os.File` value.
    f, err := os.Open("configuration.ini")
    check(err)

    // Read some bytes from the beginning of the file.
    // Allow up to 5 to be read but also note how many
    // actually were read.
    b1 := make([]byte, 10)
    n1, err := f.Read(b1)
    check(err)
    fmt.Printf("%d bytes: %s\n", n1, string(b1))

    f.Close()

}

正如您在上面的代码中看到的,b1 被定义为字节 slice ,它作为值参数传递给 Read 方法。在 Read 方法之后,b1 包含文件中的前 10 个字母。

上面的代码让我非常困惑的是,为什么 b1Read 方法之后突然包含值。

在 Golang 中,当我将值传递给方法时,它将作为值而不是引用传递。为了澄清我在说什么,我制作了一个示例应用程序:

package main


import (
    "fmt"
)

func passAsValue(p []byte) {
    c := []byte("Foo")
    p = c
}

func main() {

    b := make([]byte, 10)
    passAsValue(b)
    fmt.Println(string(b))
}

passAsValue 函数之后,b 不包含任何值,而我在 golang 中所期望的是,参数将作为值传递给函数或方法。

那为什么第一个代码片段可以改变传递参数的内容呢?如果 Read 方法需要一个 []byte slice 的指针,那么我会同意,但在这种情况下不会。

最佳答案

一切都按值传递(通过创建传递值的副本)。

但由于 Go 中的 slice 只是底层数组的连续段的描述符,描述符将被复制,它将引用相同的底层数组,所以如果你修改内容 的 slice ,相同的底层数组被修改。

如果你在函数中修改 slice 值本身,那不会在调用处反射(reflect)出来,因为 slice 值只是一个副本,副本将被修改(而不是原始 slice 描述符值)。

如果你传递一个指针,指针的值也是按值传递(指针值会被复制),但在这种情况下如果你修改pointed值,那将是与调用处相同(指针的副本和原始指针指向相同的对象/值)。

相关博客文章:

Go Slices: usage and internals

Arrays, slices (and strings): The mechanics of 'append'

关于go - Reader接口(interface)改变值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29936700/

相关文章:

mongodb - 在 Go 中随机化 MongoDB 查询的顺序

arrays - "$scalar = @array[n]"的后果是什么?

python - 列表列表的切片行为问题

javascript - Adobe Reader Javascript 打开 .DOC

c# - 如何为每个 MySQL 获取的变量创建一个包含内容的面板

go - Go中的阻塞构造函数

go - 在 Go 中转换为 int 的月份

python - 如何多次使用 csv 阅读器对象

go - 将命名类型转换为未命名类型

amazon-web-services - Docker - 无法从外部访问 docker 端口