【问题标题】:Immutable strings in GoGo 中的不可变字符串
【发布时间】:2016-08-11 18:25:42
【问题描述】:

有谁能解释一下为什么&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
}

【问题讨论】:

  • 因为c1是唯一的实例,它的地址不会改变,你只能改变它的值
  • 是的,c1 没有被更改,但它的字段 name 是不可变的,对吧?所以当我改变name 它应该有新的地址。如果我想存储非常大的字符串,编译器如何存储它,当它仍然使用相同的地址时?

标签: string pointers go immutability


【解决方案1】:

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

字符串的不变性意味着字符串中的字符不能被改变。这适用于 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)))
}

Playground

【讨论】:

猜你喜欢
  • 2015-04-15
  • 1970-01-01
  • 1970-01-01
  • 2014-09-28
  • 1970-01-01
  • 2023-03-08
  • 1970-01-01
  • 2015-07-02
  • 1970-01-01
相关资源
最近更新 更多