Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Immutable string and pointer address

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?

like image 683
Rudziankoŭ Avatar asked Nov 17 '17 14:11

Rudziankoŭ


Video Answer


1 Answers

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?

like image 159
icza Avatar answered Sep 28 '22 07:09

icza