Go中的不可变字符串

cam*_*beh 1 string pointers immutability go

有人能够解释我为什么地址&c1.name在功能改变后是相同的changeMe().我认为Go中的字符串是不可变的.

package main

import "fmt"

type customer struct {
    name string
    age  int
}

func main() {
    c1 := customer{"Todd", 44}
    fmt.Println(&c1.name) // 0x8201e4120

    changeMe(&c1)

    fmt.Println(c1)       // {Rocky 44}
    fmt.Println(&c1.name) // 0x8201e4120
}

func changeMe(z *customer) {
    fmt.Println(z)       // &{Todd 44}
    fmt.Println(&z.name) // 0x8201e4120
    z.name = "Rocky"
    fmt.Println(z)       // &{Rocky 44}
    fmt.Println(&z.name) // 0x8201e4120
}
Run Code Online (Sandbox Code Playgroud)

Grz*_*Żur 10

字符串的不变性与变量的不变性不同.

字符串的不变性意味着字符串中的字符无法更改.这适用于Go.Go在切割字符串时使用它,如下例所示.

Go中的变量总是可变的.更改字符串变量时,将更改变量的内部字段(指针和长度).变量的地址永远不会改变.

下面的示例显示了Go字符串变量的内部结构.第一个整数是字符数组的地址,第二个是长度.

请参阅Go http://research.swtch.com/godata中有关字符串内部的文章.

package main

import (
        "fmt"
        "reflect"
        "unsafe"
)

func main() {
    var x string = "abc"
    fmt.Println(x, &x, (*reflect.StringHeader)(unsafe.Pointer(&x)))
    x = "cde"
    fmt.Println(x, &x, (*reflect.StringHeader)(unsafe.Pointer(&x)))
    x = x[1:]
    fmt.Println(x, &x, (*reflect.StringHeader)(unsafe.Pointer(&x)))
}
Run Code Online (Sandbox Code Playgroud)

Playground

  • 反射包中还有[StringHeader](https://golang.org/pkg/reflect/#StringHeader),它反映了[runtime/string.go]中的实际字符串结构布局(https:// golang.组织/ src目录/运行/ string.go#L215) (2认同)