为什么说go语言中的string是不可变的?

s := "foobar阿斯蒂芬"
fmt.Println(s)
fmt.Println(&s)
s="qweqweqweqweqwe"
fmt.Println(s)
fmt.Println(&s)

这个不可变到底指的是啥意思?上面的代码不就使s这个string变量改变了吗?而且s的地址也没有变化(说明没有给s重新分配内存),那这样看来,s就是可变的呀,实在不懂,求解惑

已邀请:

tpkeeper - Software Engineer. Gopher. [ tpkeeper.me@gmail.com ]

赞同来自: Hawken

1、string不可变是指存放 "foobar阿斯蒂芬" 的内存区域不可变
2、s是一个变量,s的地址不会变,但s的值会变,s的值即是"foobar阿斯蒂芬"的地址
3、当s="qweqweqweqweqwe"时,变量s的值也相应的变成了"qweqweqweqweqwe"的地址,但s的地址并没有变


总结:楼主大概是混肴了变量s的地址和字符串string的地址

simple - 分布式 & Java & Go

赞同来自: ddxx11223

从reflect包下的
type StringHeader struct {
Data uintptr
Len int
}
可以看出 string类型的变量包含 两个字段,Data中存放的是 字符串实际存放位置 的地址,string的不可变性就是指 Data字段指向的位置是一个不可修改的内存区域。但string变量本身的 Data和Len字段的值是可以改变的。


下面一段程序用来验证 : Data字段指向的位置是一个不可修改的内存区域


// 将string变量转换为[]byte变量,string和[]byte变量之间将共享 Data字段指向的 真实数据。
// 如果直接用 []byte(s) 这种方式转换,string和[]byte变量之间之间不共享 底层数据(会有新的
// 内存分配)
func str2bytes(s string) []byte {
sh := (reflect.StringHeader)(unsafe.Pointer(&s))
bh := &reflect.SliceHeader{
Data: sh.Data,
Len: sh.Len,
Cap: sh.Len,
}
return
(*[]byte)(unsafe.Pointer(bh))
}


// 测试代码
s := "abcd"
b := str2bytes(s)
b[0] = 98 // 通过切片b 操作s.Data指向的底层数据,会出现panic,说明s.Data指向的区域是不可修改的内存

Mephis_Pheies

赞同来自:

你无法修改s中的某个字符,你只能重新创建一个字符串


s = s[:2] + "a" + [3:]

要回复问题请先登录注册