In Go spec is written:
Strings are immutable: once created, it is impossible to change the contents of a string.
I have following code:
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
I would have expected &str
address was changed after *ptr = "world"
. As it would happen with Java, where we reassign String references.
What is 'immutability' here?
string
values are immutable.
str
is not a string
value. It's a variable (of string
type). And values of variables may be changed, that's what you'd expect from any programming language.
"hello"
is a string
value, and this is what is immutable. "world"
is another string
value, and when you assign "world"
to str
, you just assign another, different value to the str
variable. It doesn't matter if you're doing it directly to str
, or via a pointer. You're just changing the value of the variable denoted by str
.
Immutable means you cannot take the string
value "world"
, and change its second character for example. If you have a function for example which receives a string
argument, whatever it receives (e.g. "hello"
), you can be sure it will always remain the same. No matter when / how you print this string
value, it will always be "hello"
.
A string
value is a struct value under the hood, represented by the reflect.StringHeader
type:
type StringHeader struct {
Data uintptr
Len int
}
It basically stores a data pointer (to the byte array holding the UTF-8 encoded value of the text), and the byte-length of the string
value. The data array and its length are not exposed to you, so you can't modify them. This is one element of making sure that string
values are immutable. Another element is that although string
values can be indexed (which indexes its bytes), you can not assign new values to the index expressions. E.g. it is valid to use the value "abc"[0]
, but it is invalid to assign a new value to it like "abc"[0] = 'x'
. Similarly, you cannot take the address of an index expression indexing a string
value (else you could modify the pointed value and thus indirectly the string
value).
This is what the language spec guarantees. Note that there are certain ways to still change string
values, e.g. using package unsafe
, but this falls outside the guarantees of the spec:
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.
The "moment" you import package unsafe
, you'll lose any guarantees and safety provided by the language spec, and from there on you can't complain for anything. But without using these "special" means, it cannot happen that a string
value gets altered.
Read the blog post Strings, bytes, runes and characters in Go for how string
is implemented and works in Go.
See related questions:
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?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With