围棋 spec写成:
Strings are immutable: once created, it is impossible to change the contents of a string.
我有以下代码:
str := "hello"
fmt.Printf("%p\n",&str) // 0x1040c128
fmt.Printf("%v\n",str) // hello
ptr := &str
*ptr = "world"
fmt.Printf("%p\n",&str) // 0x1040c128
fmt.Printf("%v\n",str) // world
我本以为 &str
地址在 *ptr = "world"
之后发生了变化。就像在 Java 中发生的那样,我们重新分配 String 引用。
这里的“不变性”是什么?
最佳答案
string
values 是不可变的。
str
不是 string
值。它是一个变量(属于string
类型)。变量的值可能会改变,这是您对任何编程语言的期望。
"hello"
是一个 string
值,这是不可变的。 "world"
是另一个 string
值,当你将 "world"
赋给 str
时,你只是赋值另一个, str
变量的不同值。无论您是直接对 str
执行此操作,还是通过指针执行此操作都没有关系。您只是在更改由 str
表示的变量的值。
不可变意味着您不能使用string
值"world"
,并更改它的第二个字符。例如,如果您有一个接收 string
参数的函数,无论它接收到什么(例如 "hello"
),您都可以确保它始终保持不变。无论何时/如何打印此 string
值,它始终是 "hello"
。
string
值是引擎盖下的结构值,由 reflect.StringHeader
表示输入:
type StringHeader struct {
Data uintptr
Len int
}
它基本上存储了一个数据指针(指向保存文本的 UTF-8 编码值的字节数组)和 string
值的字节长度。数据数组及其长度不会向您公开,因此您无法修改它们。这是确保 string
值不可变的要素之一。另一个要素是,尽管可以对 string
值进行索引(索引其字节),但您不能为索引表达式分配新值。例如。使用值 "abc"[0]
是有效的,但是给它分配一个新值是无效的,比如 "abc"[0] = 'x'
.同样,您不能获取索引 string
值的索引表达式的地址(否则您可以修改指向的值,从而间接修改 string
值)。
这就是language spec保证。请注意,仍有某些方法可以更改 string
值,例如使用包 unsafe
,但这超出了规范的保证范围:
Package unsafe contains operations that step around the type safety of Go programs.
Packages that import unsafe may be non-portable and are not protected by the Go 1 compatibility guidelines.
当你导入包 unsafe
的“那一刻”,你将失去语言规范提供的任何保证和安全,从那时起你就不能提示任何事情了。但是如果不使用这些“特殊”方法,string
值就不会发生改变。
阅读博文 Strings, bytes, runes and characters in Go了解 string
在 Go 中是如何实现和工作的。
查看相关问题:
What is the difference between the string and []byte in Go?
What are the possible consequences of using unsafe conversion from []byte to string in go?
关于string - 不可变字符串和指针地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47352449/