Go语言 字符串是引用类型还是值类型

afdcj2ne  于 2023-02-27  发布在  Go
关注(0)|答案(1)|浏览(153)

我最近在阅读go的源代码,看到源代码中有一个名为string.go的文件,但同时,字符串是预先声明的标识符,而且它也被直接用在源代码中?
我发现一些文章说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)
}

output: 
=== 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,它应该在某个地方定义行为?
我真的很困惑

i7uq4tfw

i7uq4tfw1#

&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
参见相关问题:
不可变字符串和指针地址
Go语言中的string和[] byte有什么区别?

相关问题