不可变的字符串和指针地址

Rud*_*koŭ 4 string immutability go

在Go 规范中写道:

字符串是不可变的:一旦创建,就不可能改变字符串的内容.

我有以下代码:

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  
Run Code Online (Sandbox Code Playgroud)

&str原本预计地址会改变*ptr = "world".正如Java所发生的那样,我们重新分配字符串引用.

什么是"不变性"?

icz*_*cza 12

string 是不可变的.

str不是一个string价值.它是一个变量(string类型).变量的值可能会改变,这就是你对任何编程语言的期望.

"hello"是一个string值,这是不可变的."world"是另一个string值,当您指定"world"str,您只需为str变量分配另一个不同的值.如果您直接str或通过指针进行操作并不重要.您只是更改由表示的变量的值str.

不可变意味着您无法获取string"world",例如更改其第二个字符.如果你有一个函数,例如接收一个string参数,无论它收到什么(例如"hello"),你可以确定它将始终保持不变.无论何时/如何打印此string值,它始终是"hello".

string值是在引擎盖下一个struct值,由表示的reflect.StringHeader类型:

type StringHeader struct {
    Data uintptr
    Len  int
}
Run Code Online (Sandbox Code Playgroud)

它基本上存储一个数据指针(到保存文本的UTF-8编码值的字节数组),以及值的字节长度string.数据数组及其长度不会向您公开,因此您无法修改它们.这是确保string值不可变的一个要素.另一个元素是虽然string可以索引值(索引其字节),但是不能为索引表达式分配新值.例如,使用该值是有效的"abc"[0],但是为它分配新值是无效的"abc"[0] = 'x'.同样,您不能将索引表达式的地址索引为索引string值(否则您可以修改指向的值,从而间接修改string值).

这是语言规范保证的.请注意,仍有某些方法可以更改string值,例如使用包unsafe,但这不符合规范的保证:

Package unsafe包含围绕Go程序类型安全的操作.

导入不安全的软件包可能是不可移植的,并且不受Go 1兼容性指南的保护.

您导入包装的"时刻" unsafe,您将失去语言规范提供的任何保证和安全,从那里您不能抱怨任何事情.但是,如果不使用这些"特殊"手段,string价值就不会发生变化.

阅读博客文章Go中的字符串,字节,符文和字符,了解如何在Gostring中实现和工作.

查看相关问题:

Go中的字符串和[]字节有什么区别?

go中使用从[] byte到string的不安全转换可能带来的后果是什么?

  • 要扩展,"字符串"变量基本上是修改后的切片标头.字符串头本身位于内存中的某个位置(在您的示例中为"0x1040c128"),内存中的该位置包含两个值,一个指向底层数组的指针和字符串的大小(与切片不同,字符串没有"容量"值,因为,它是不可变的,它们的容量总是等于它们的长度).分配给字符串变量时,您正在更改_ header_中存储的指针的值.标题的地址本身不会改变. (3认同)
  • 我还要补充说[this](https://blog.golang.org/slices)和[this](https://blog.golang.org/strings)(按此顺序)是必读的宝贝地鼠.;-) (2认同)