我对阅读器界面有疑问,定义如下:
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
被定义为字节切片,并作为value参数传递给Read
方法。在Read
方法之后,b1
包含文件中的前10个字母。
对于我上面这段代码非常困惑的是,为什么b1
在Read
方法之后突然包含值。
在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
切片的指针,那么我会同意,但在这种情况下不是。
答案 0 :(得分:2)
所有内容都按值传递(通过创建传递的值的副本)。
但是由于Go中的切片只是基础数组的连续段的描述符,因此将复制描述符,该描述符将引用相同的基础数组,因此如果您修改内容切片的,修改了相同的底层数组。
如果在函数中修改切片值本身,则不会在调用位置反映切片值,因为切片值只是一个副本,并且将修改副本(而不是原始切片描述符值)。
如果传递指针,指针的值也会按值传递(指针值将被复制),但在这种情况下,如果修改指向的值,那将是与在调用位置相同(指针的副本和原始指针指向同一个对象/值)。
相关博客文章:
答案 1 :(得分:1)
Go中的切片标头本身包含指向底层数组的指针。
您可以阅读官方博客文章:https://blog.golang.org/slices
即使切片标头按值传递,标头也包含指向数组元素的指针,因此原始切片标头和传递给函数的标头副本都描述了相同的数组。因此,当函数返回时,可以通过原始切片变量看到修改后的元素。
答案 2 :(得分:0)
与在C
中传递指针的行为完全相同:
#include <stdio.h>
#include <stdlib.h>
// p is passed by value ; however, this function does not modify p,
// it modifies the values pointed by p.
void read(int* p) {
int i;
for( i=0; i<10; i++) {
p[i] = i+1;
}
}
// p is passed by value, so changing p itself has no effect out
// of the function's scope
void passAsValue(int*p) {
int* c = (int*)malloc(3*sizeof(int));
c[0] = 15; // 'F' in hex is 15 ...
c[1] = 0;
c[2] = 0;
p = c;
}
int main() {
int* p = (int*)malloc(10*sizeof(int));
int i;
for( i=0; i<10; i++) {
p[i] = 0;
}
printf(" init : p[0] = %d\n", p[0]);
read(p);
printf(" after read : p[0] = %d\n", p[0]);
passAsValue(p);
printf("after passAsValue : p[0] = %d\n", p[0]);
return 0;
}
输出:
// init : p[0] = 0
// after read : p[0] = 1
//after passAsValue : p[0] = 1 // <- not 15, the modification from
// // within passAsValue is not persistent
(对于记录:此C程序泄漏int* c
数组)
Go
切片包含的信息多于指针:它是一个小结构,包含分配数组的指针,长度和最大容量(请参阅其他答案中提到的链接:{ {3}})
但从代码的角度来看,它的行为与C
指针完全相同。