<p>This was pointed out by a friend of mine, though I never got the time into actually sit and find out. So I thought I could take the easy way out, ask you guys.</p>
<pre><code>package main
import "fmt"
func main() {
a := "hello"
fmt.Println(&a)
a = a + " there"
fmt.Println(&a)
a = "world"
fmt.Println(&a)
}
</code></pre>
<p>This seemingly simple code, produces the following results (on golang.org):</p>
<pre><code>0x1040a120
0x1040a120
0x1040a120
Program exited.
</code></pre>
<p>Could someone please help me understand why all 3 of them have the same address (despite <a href="https://golang.org/ref/spec#String_types">string being immutable in Go</a>)? Is it because of some clever memory allocation during run-time?</p>
<p>P.S: This whole thing might have arose from my misunderstanding of what <em>Immutable</em> is. Please help me understand if that's the case too.</p>
<hr/>**评论:**<br/><br/>pobody: <pre><p>The actual strings, like "hello" and "world" are immutable. But all that means is somewhere in memory the string "hello" exists and Go will not change the contents of that memory location.</p>
<p>Strings are slices of bytes. But you can't access the underlying array directly like you could a typical slice. The string type is abstracting this away for you. In other words, when you ask for <code>&a</code>, you are getting the address of another pointer, not the address of the start of the actual data "hello".</p>
<p>One way to see this is to look at a subslice:
<a href="https://play.golang.org/p/KWccuJsFpj">https://play.golang.org/p/KWccuJsFpj</a></p>
<p>Note how <code>b</code> (a subslice of <code>a</code>) doesn't change even though <code>a</code> does. <code>b</code> is pointing to a subslice of the string "hello", which <code>a</code> <em>used</em> to also point to, but no longer does. </p>
<p>For another way to look at this, see the "Strings" section of <a href="http://research.swtch.com/godata">http://research.swtch.com/godata</a>.</p></pre>kamaleshbn: <pre><p>Awesome, that was crystal clear, thank you! :)</p></pre>uncle_bad_touches: <pre><p>You are printing out the address of the string header on the stack (see <a href="https://golang.org/pkg/reflect/#StringHeader">https://golang.org/pkg/reflect/#StringHeader</a>). What you want to look at is reflect.StringHeader.Data where the actual contents of the string is stored.</p></pre>materialdesigner: <pre><p><a href="https://groups.google.com/forum/m/#!topic/golang-nuts/EXvylZB6ILk">https://groups.google.com/forum/m/#!topic/golang-nuts/EXvylZB6ILk</a></p>
<p>Tl;dr string variables are mutable, but string <em>values</em> (I.e. The array backing the string) is immutable</p></pre>tv64738: <pre><p><code>42</code> is immutable too. <a href="https://play.golang.org/p/USGq-LOjtK" rel="nofollow">https://play.golang.org/p/USGq-LOjtK</a></p>
<pre><code>package main
import "fmt"
func main() {
a := 42
fmt.Println(&a)
a = a + 13
fmt.Println(&a)
a = 7
fmt.Println(&a)
}
</code></pre>
<p>Yet the variable stays in the same memory location, the same way:</p>
<pre><code>0x1040e0f8
0x1040e0f8
0x1040e0f8
</code></pre></pre>kamaleshbn: <pre><p>Umm, <code>int</code> is <em>mutable</em>, and what you have here is the expected output.</p>
<p>P.S: Number types are mutable in almost all programming languages (as far as I know), and the reason is very simple, when you create a <code>number</code> type variable, it's allocated a fixed memory based on the number type you choose (int, int64, float, uint etc.), i.e. it takes the same amount of memory to save <code>1</code> or <code>999999</code>. And changing the value of the number would <em>overwrite</em> on the same memory location as it was initially. Strings on the other hand, occupy 1 byte per character, and they are variable in size, so the compiler cannot allocate a set memory size beforehand.</p></pre>wot-teh-phuck: <pre><blockquote>
<p>occupy 1 byte per character,</p>
</blockquote>
<p>Err, that's not the case assuming by character you mean a "visual character".</p></pre>kamaleshbn: <pre><p>You're absolutely right, <em>unfortunately</em> I just think of alphabets when I talk <em>string</em>. And by <em>character</em> I just mean 1 alphabet. I know this is wrong, considering a lot of characters occupy 2+ bytes. Sorry again, it's just a weird habit I think.</p></pre>tv64738: <pre><p>I think what you're trying to say there is that variables are variable. That includes string variables. And int.</p></pre>TheMerovius: <pre><p>Because a string is, essentially, a struct that holds a pointer and a length. This is necessarily so, so that the compiler knows the size of a <code>string</code> at compile time (e.g. when passed as arguments) and it makes slicing more efficient, because two slices can share memory, but have differing lengths.</p>
<p>Assigning anything to it, overwrites that struct, but it won't mutate the memory that string is pointing to. That is, what is meant when we say "strings are immutable".</p>
<p>When you look at <code>&a</code>, you are taking the address of that struct. You can also unpack the address of the <a href="https://play.golang.org/p/U8kIn3Xn4y">underlying memory</a> to see how this is working.</p>
<p>A different way to look at it, is that <code>a</code> is not a <code>string</code>, but a <code>string</code> <em>variable</em>. By doing <code>a := "hello"</code> you are saying "declare a variable with name <code>a</code> of type <code>string</code> and store the string <code>"hello"</code> in it". The string remains immutable, but the variable is mutable (or indeed… variable :) which is why they are called that).</p>
<p>Contrast that with <code>[]byte</code>. You can store a <code>[]byte</code> in a variable, but you can not only reassign the variable, you can also change the memory that <code>[]byte</code> points at (and thus also influence all the variables that have the same <code>[]byte</code> stored in it), so to speak.</p></pre>ultra_brite: <pre><p>Your biggest problem is that you don't understand what a pointer is. I would study this at first place if I were you. I pointer is just an address, it has nothing to do with the value of a variable or how it is stored.</p></pre>BraveNewCurrency: <pre><blockquote>
<p>Your biggest problem is that you don't understand what a pointer is.</p>
</blockquote>
<p><em>No.</em> I have dozens of years experience in C and kernel programming. I do, in fact, know what a pointer is. But I was just as confused about the output as the OP.</p>
<blockquote>
<p>pointer is just an address, it has nothing to do with the value of a variable or how it is stored.</p>
</blockquote>
<p>That is correct, but meaningless in this context. It turns out that the variable <code>a</code> does NOT point to the string, but to an intermediate structure that eventually points to the string. The extra level of indirection is <em>specific to Go</em>, so people can be familiar with pointers but still not be magically know why this program does what it does.</p>
<blockquote>
<p>I would study this at first place if I were you.</p>
</blockquote>
<p>I downvoted your post for being wrong and coming across as condescending. This problem had <em>nothing</em> to do with understanding pointers.</p>
<p>(P.S. We would say the above phrase as "I would study this first, if I were you". The phrase "First Place" is mostly used for winning a competition, although sometimes it can be used like this: "You should have known that in the first place".)</p></pre>SteveMcQwark: <pre><blockquote>
<p>That is correct, but meaningless in this context. It turns out that the variable <code>a</code> does NOT point to the string, but to an intermediate structure that eventually points to the string. The extra level of indirection is <em>specific to Go</em>, so people can be familiar with pointers but still not be magically know why this program does what it does.</p>
</blockquote>
<p>I'm not sure it's useful to think of the variable itself as pointing to something. The variable <em>holds</em> a structure which is the string value itself, which <em>points to</em> the character data. There's one level of indirection, which is the same as in most variable length string representations (aside from short string optimizations and such). <code>const char*</code> in C has the same amount of indirection, and the same mutability characteristics. You can reassign the <code>string</code> variable as much as you want, you just can't mutate the character data pointed to by a particular string value. And reassigning the variable doesn't change its address, which is what the OP was observing.</p>
<p>The important thing to remember with Go is that there's nothing like C++ references going on. While we can call strings a reference type, they aren't implicitly dereferenced. The reference itself is a first class value, so taking the address of the string takes the address of the reference and not of the backing data.</p></pre>ultra_brite: <pre><p>lol butt hurt? you're so smart you can't even take 30 minutes to read Go specification ? If you did you wouldn't be confuse about what a pointer is in Go. 12 years of experience in this or that is meaningless when you can't understand the difference between Go and C at first place.</p></pre>BraveNewCurrency: <pre><blockquote>
<p>lol butt hurt?</p>
</blockquote>
<p>No, I was merely pointing out that "knowing pointers" does not explain the original program.</p>
<blockquote>
<p>you're so smart you can't even take 30 minutes to read Go specification ?</p>
</blockquote>
<p>I did. And I just looked again. I didn't see any explanation that "taking the value of a string give you a pointer to a struct, not the string data itself." Am I missing something or did you not "take 30 minutes"?</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传