字符串是引用类型还是值类型?

huangapple go评论76阅读模式
英文:

Is string a reference type or a value type

问题

我最近在阅读Go的源代码。我看到源代码中有一个名为string.go的文件,但同时,string也是预声明的标识符,并且在源代码中直接使用了它。

我找到一些文章说string是引用类型。但是我尝试运行了下面的代码:

func TestString(t *testing.T) {
    s := "abc"

    fmt.Println("address of s: ", &s)

    xx := func(sss string) {
        fmt.Println("address of sss: ", &sss)
        sss = "123"
    }

    xx(s)

    fmt.Println("value of s after sss modified the content: ", s)
}

输出结果为:

=== RUN   TestString
address of s:  0xc00010a560
address of sss:  0xc00010a570
value of s after sss modified the content:  abc
--- PASS: TestString (0.00s)

如果string是引用类型,那么当我将s传递给func(sss string)时,sss的地址应该与s相同,并且s应该被修改,但实际上并没有,为什么呢?

Go是否对string做了一些处理,使其看起来像值类型?但是这段代码在哪里?如果string是引用类型,实际类型是type stringStruct,那么应该在某个地方定义了它的行为。

这真的让我困惑不已。

英文:

I was recently reading the source code of go. I see that there is a file called string.go in the source code, but at the same time, the string is the predeclared identifiers, and it also being used in the source code directly?

I found some article that said string is the reference type. but I try to run the following code:

func TestString(t *testing.T) {
	s := "abc"

	fmt.Println("address of s: ", &s)

	xx := func(sss string) {
		fmt.Println("address of sss: ", &sss)
		sss = "123"
	}

	xx(s)

	fmt.Println("value of s after sss modified the content: ", s)
}

output: 
=== RUN   TestString
address of s:  0xc00010a560
address of sss:  0xc00010a570
value of s after sss modified the content:  abc
--- PASS: TestString (0.00s)

if the string is reference, So when I pass the s to func(sss string), the address of sss should be the same with s, and s should be modified, but it wasn't, why?

Is the go did something of string, let it seems like a value type? but where is the code? if the string is a refernce type and the actual type of string is type stringStruct, it should be defined the behavior somewhere?

It really confuse me

答案1

得分: 3

&s&sss是变量的地址。由于它们是两个不同的非零大小变量,它们的地址必须不同,这就是你所经历的情况。

在Go语言中,没有经典C语言意义上的引用类型。string是一个类似结构体的小值,由reflect.StringHeader描述:

type StringHeader struct {
    Data uintptr
    Len  int
}

它包含一个指针,指向存储字符串的UTF-8编码字节的位置,以及一个字节长度。

当你将某个值赋给string类型的变量时,你改变的是变量的值(上述小的StringHeader结构体),而不是指向的数据。当你将某个值赋给sss变量时,原始的s变量不会改变,它仍然包含指向相同字节的相同数据指针。

阅读The Go Blog: Strings, bytes, runes and characters in Go

参考相关问题:

https://stackoverflow.com/questions/47352449/immutable-string-and-pointer-address/47352588#47352588

https://stackoverflow.com/questions/32625959/what-is-the-difference-between-the-string-and-byte-in-go/32626057#32626057

英文:

&s and &sss are the addresses of variables. Since they are 2 distinct non-zero size variables, their addresses must be different, which you experience.

There are no reference types in Go in the classic C sense. A string is a small struct-like value described by reflect.StringHeader:

type StringHeader struct {
    Data uintptr
    Len  int
}

It contains a pointer where the UTF-8 encoded bytes of the string are stored, and a byte-length.

When you assign something to a variable of string type, you change the value of the variable (the above small StringHeader struct), but not the pointed data. When you assign something to the sss variable, the original s variable is unchanged, it still contains the same data pointer pointing to the same bytes.

Read The Go Blog: Strings, bytes, runes and characters in Go

See related questions:

https://stackoverflow.com/questions/47352449/immutable-string-and-pointer-address/47352588#47352588

https://stackoverflow.com/questions/32625959/what-is-the-difference-between-the-string-and-byte-in-go/32626057#32626057

huangapple
  • 本文由 发表于 2023年2月20日 01:41:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/75502153.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定