<p>Hello all.</p>
<p>To be honest, I feel bad to ask here that beginner problem (this subreddit looks like adressed to rather mature programmers than to beginners) - but I'm unable to find these information elsewhere. </p>
<p>After A Tour of Go, some books, and hours googling & trying I still don't understand some pointer's essentials. </p>
<p>Cutting to the chase, I'm trying to change field of global struct. Unfortunately, most of examples are about using structs locally and I have problems to translate it for global usage. Also, I need to pass struct by some functions.</p>
<p>I create struct in this way</p>
<pre><code>type Place struct {
name string
x, y int
}
var Bromberg Place
var Thorn Place
func InitPlace() {
Bromberg = Place{"Bromberg", 0, 0}
Thorn = Place{"Thorn", 0, 0}
}
</code></pre>
<p>then I'm passing it by some function then try to change x of specific city</p>
<pre><code>function ChooseCity
variable city type-Place
if random(100) <= 50
city is Bromberg
else
city is Thorn
run function do_something_else_with_city with argument city
func do_something_else_with_city with argument city
do_something
run function ChangeX with argument city
function ChangeX with argument city
change city.x
</code></pre>
<p>In that case, do I need to pass argument with pointer every time? </p>
<p>I was trying to use receiver <a href="http://stackoverflow.com/questions/11810218/how-to-set-and-get-fields-in-golang-structs">as here</a>, and simply use example from A Tour of Go, but every time change of x was temporary. How should I deal with it?</p>
<p>Respectfully,
Pors</p>
<hr/>**评论:**<br/><br/>PsyWolf: <pre><p>I wanna reply to one specific part of your question that no one seems to have covered.</p>
<blockquote>
<p>In that case, do I need to pass argument with pointer every time? </p>
</blockquote>
<p>Yes you do, but not explicitly. Check out
<a href="https://play.golang.org/p/lylFAxW6Tb" rel="nofollow">https://play.golang.org/p/lylFAxW6Tb</a></p>
<p>In well written go, most variables in your program fall into 1 of 2 categories</p>
<ul>
<li>Always used as a value</li>
<li>Always used as a pointer </li>
</ul>
<p>It's relatively rare that you actually need to treat a variable sometimes as a value and other times as a pointer. By declaring your variable the right way up front, you won't have to use &s and *s everywhere it get it to compile. </p></pre>SomeoneUnsuspicious: <pre><p>For now I'm going to stick with all these & and * to get more used to this mechanics, but in general it seems really useful. No problems if some structs are assigned to one type?</p></pre>sicueft: <pre><p>I think the & and * are confusing because whenever people are talking about those <em>operators</em>, they use terminology without explaining the terminology and how the positions of the symbols matters. For instance, what does (var p *int) even mean to someone who doesn't know how memory is allocated in a program? It should really be explained step by step in the simplest way possible, so I'll try with some examples. Lets start with:</p>
<p>var p *int : this means that variable p <em>is</em> a pointer <em>to</em> a value of the datatype int. </p>
<p>a := p : this would initialize a variable called "a" that is a pointer <em>of</em> the same value as p <em>to</em> a value of datatype int. So pointers are values in this way and they hold the <em>memory address</em> of whatever value they're referencing. "a" and "p" would be two variables in two <em>different</em> address spaces but would <em>hold</em> that same value. Every new variable you create has its own address space. If you want to refer to a variable using only one address space, don't declare any new variables!</p>
<p>*p : this is very different from (var p *int) because notice the position of the (*) and <em>this is simply syntax</em>. In fact, it's confusing because this is <em>not</em> a pointer. It's called <em>dereferencing</em> (because pointers <em>reference</em>) and it gets that value of datatype int instead of returning the address which would just be plain "p". In this case, the output would be <nil> because we haven't pointed "p" to anything.</p>
<p>&p : this tells you the memory address of the variable "p" that was instantiated in this program.</p>
<p>*p = 1 : this would <em>throw an error</em> because "p" is not pointing to anything so you can't set the value of a nonexistent variable to a value. So instead declare a variable of int value first and then point p to it. (z := 1) then, (p = &z). Then you can change the value of "z" through "p" like (*p = 2) then "z" will equal 2.</p>
<p>b := *p : this would be how you <em>get</em> (rather than <em>set</em>) the value of datatype int that p is pointing to. (*p) is the value that is at the address value "p". Again, (*p) is <em>not</em> a pointer and neither is "b". They are the values <em>of</em> the pointer "p" (which is an instantiated variable), in this case "z".</p>
<p>c := &b (==) c:= &(*p) (==) c:= p : this would initialize a variable "c" that <em>gets</em> the <em>memory address</em> of the value "b" (or *p) and this <em>is</em> a pointer because the value that "c" holds is a <em>memory address</em>. &b is <em>not</em> a pointer, the variable "c" is the pointer. Remember to distinguish <em>operations</em> from <em>variables</em> and <em>values</em>, which are all different things.</p>
<p>d := &c (==) d := &(&(*p)) : d is a pointer <em>of</em> a pointer. It holds the memory location of the variable c which holds the memory location of "b" which is a value of datatype int. </p>
<p>e := &(&c) : this would <em>throw an error</em> because &c <em>isn't</em> a variable with a memory address so you can't get an address for it. Remember that "d" and "&c" are two <em>different</em> things. e := &(d) would work just fine because "d" has an address somewhere because it was initialized in the program.</p>
<p>f := *(&c) : "f" would be the value of the address space of the pointer "b". Why is that? (&c) gets you the address for "c" and "c" is a pointer to "b" from (c := &b), and <em>not</em> (c:= &(*p)) since (*p) is an operation and not a variable. That means if we deference (&c) we get the value in the address space <em>of</em> "c" which is the address for "b" (c := &b).</p></pre>civeng12: <pre><p>This really helped me, thanks!</p></pre>sicueft: <pre><p>No problem, always glad to teach and learn.</p></pre>PsyWolf: <pre><blockquote>
<p>No problems if some structs are assigned to one type? </p>
</blockquote>
<p>I don't understand this question. Can you clarify?</p></pre>SomeoneUnsuspicious: <pre><p>I figured it out. Silly me, I'd say :D I was mislead because * is next to type, and I thought that declaring var Thorn *Place could overwrite Place for whole eternity.</p></pre>mrfrobozz: <pre><p>I'm glad that you got some good help here, but if you do want to, the <a href="https://blog.gopheracademy.com/gophers-slack-community/" rel="nofollow">Golang Slack</a> has a newbies channel to help with beginners. I've found excellent help there in the past.</p></pre>divan0: <pre><p>Hi,</p>
<p>so imagine your variables as a real world objects - you have two: Bromberg and Thorn. Also, imagine two fingers, one is pointing to the Bromberg, another pointing to the Thorn - that's your pointers.</p>
<p>Now, if you call a function with parameter, Go will copy the parameter, so only function can work with it. If you pass the "real object" - Go will copy it, so changing x will mean changing x of the copied object. Instead, if you pass a pointer, it will be copied as well, but still will point to the right object, which you will modify.</p>
<p>Sorry for that simplistic explanation, but that's how it essentially is. Does that make sense?</p></pre>SomeoneUnsuspicious: <pre><p>It does make sense, thank you for explaination. Altought I know theory already. I have more problems with pointers syntax - for example, I'm not sure why sometimes I need use just & (as for scanning input) but sometimes I need use both & and *. Doesn't scanned input need to check for memory adress? Theory basics sounds simple, but differences in using it in different cases are not clear for me.</p></pre>chewxy: <pre><ul>
<li><code>&x</code> is the operation to get the address of the variable <code>x</code></li>
<li><code>var x *foo</code> is a declaration that <code>x</code> is a pointer to <code>foo</code></li>
<li><code>a = *x</code> is an operation to dereference <code>x</code></li>
</ul>
<p>A majority of the problem is the overloaded semantics of the <code>*</code> symbol, really.</p>
<p>Let's look at a real life code:</p>
<pre><code>var buf bytes.Buffer
fmt.Fprintf(&buf, "hello %v", "someone unsuspicious")
</code></pre>
<p>Here we declare <code>buf</code> to be a <code>bytes.Buffer</code> in the first line. In the second line, we want to pass this <code>buf</code> to <code>fmt.Fprintf</code> which takes a <code>*bytes.Buffer</code> (it actually takes a <code>io.Writer</code> which only <code>*bytes.Buffer</code> fulfils, not <code>bytes.Buffer</code>, but we'll just say it for simplicity). </p>
<p>How do we pass a pointer to the <code>bytes.Buffer</code> object? We take the address of the variable <code>buf</code>, by using <code>&buf</code>. </p>
<p>Can we do something like this?</p>
<pre><code>var buf *bytes.Buffer = new(bytes.Buffer)
fmt.Fprintf(buf, "Blah")
</code></pre>
<p>Yes we can. I'll leave it to you to figure out the differences</p></pre>yourewelcome_bot: <pre><p>You're welcome.</p></pre>LadyDascalie: <pre><p>Check this out: <a href="https://play.golang.org/p/WBylHTnl7g" rel="nofollow">https://play.golang.org/p/WBylHTnl7g</a></p>
<p>Basically, when passing the city as an argument, you're passing in a copy of it to said function, so you're only ever working on that copy, within the limited scope of that function.</p>
<p>By using the <code>&</code> operator instead, you're telling the function to work on the original struct you're referring to, therefore, your changes stick!</p>
<p>Does that make sense?
It's probably badly explained, but hopefully that can help you understand it</p>
<p>EDIT: <a href="https://play.golang.org/p/fIUXRuJ80a" rel="nofollow">https://play.golang.org/p/fIUXRuJ80a</a>
This should let you see exactly what I mean, I'm printing the addresses of the structs that get passed in and used by the functions</p></pre>SomeoneUnsuspicious: <pre><p>Great explaination, it made pointers more understand-able for me, thank you. Still I'm not sure if everything is clear for me, but just tinkered with some samples I found problematic and I can solve it, so - I suppose I get basics finally. Thank you very, very much</p></pre>LadyDascalie: <pre><p>You are very welcome!</p></pre>gac_web: <pre><p>Pointers are values like structs or numbers. In fact, pointers are integers.</p>
<p>But they have a special functionality: they are numbers that refer to another value. They are an address, like 0xe4a5 or 0x2af6 and go is aware of that. When you pass any value to a function, that value is copied, NO EXCEPTION. If you pass a struct value to a function and you change the value inside the function, you change a copy of the struct value and not the struct value itself.</p>
<pre><code>foo := SomeStruct{x:1}
add1toX(foo) // func(f SomeStruct)
// foo.x is still 1
</code></pre>
<p>In order to change the struct value outside the function you need to pass a pointer to that struct instead of the struct itself.
The value of the pointer is the address of the struct in your computer's memory, ( 0x5a9b17 for instance )
That way Go knows that you are referring to the outer struct and not a copy and when you do f.x = f.x + 1 , go will know that f is a pointer that points to SomeStruct foo and has a field x. It is called de-referencing.</p>
<pre><code>foo := SomeStruct{x:1}
add1toX(&foo) // func(f *SomeStruct)
// foo.x is now 2
</code></pre>
<p>You can also declare a pointer to struct directly</p>
<pre><code>foo := &SomeStruct{x:1}
add1toX(foo) // func(f *SomeStruct)
// foo.x is now 2
</code></pre>
<p>Remember that any time you have an operation involving changing a value inside a function call, you need to pass a pointer to that value and not the value directly, or the value will just be copied and any change on the copy won't affect the original value.</p>
<p>So all you need to remember is that : </p>
<ul>
<li><p>pointers are integers. </p></li>
<li><p>when a value is passed to a function that value IS ALWAYS COPIED. and any modification inside the function will not affect the original value</p></li>
<li><p>in order to refer to the same value inside the function and outside the function, a pointer to that value needs to be passed to the function instead of the value itself. </p></li>
</ul>
<p>So most of the time & means "take the address of that variable" and reference this address instead of that variable directly.</p>
<p>But when you write a function in Go, you need to use * which is means : accept a pointer of something as an argument.</p>
<p>so & is for getting a pointer of something , * is for accepting a pointer of something. Now imagine you want to replace an integer inside a function.</p>
<p><a href="https://play.golang.org/p/PsvJ5QJJ2v" rel="nofollow">https://play.golang.org/p/PsvJ5QJJ2v</a></p>
<pre><code> a := 1 // a is an integer value
func(integerPtr *int){
// integerPtr is a pointer to an integer
// replacing 1 with 10
*integerPtr = 10
}(&a) // take and pass the address of a
// a is now 10
</code></pre>
<p>This is the only time when you need to use * ouside a function signature. it means replace the value of whatever pointer with another value.</p></pre>beknowly: <pre><blockquote>
<p>I was trying to use receiver as here, and simply use example from A Tour of Go, but every time change of x was temporary. How should I deal with it?</p>
</blockquote>
<p><a href="https://play.golang.org/p/HUqBoAPhRU" rel="nofollow">https://play.golang.org/p/HUqBoAPhRU</a></p>
<p>Most of the time, you should default to using pointer receivers in Go, unless you specifically need a value receiver. This isn't a hard rule, but is handy to keep in mind.</p>
<p>Value receiver:</p>
<pre><code>func (p Place) updateFieldValue() {
// p is changed _only_ here in the function,
// it will not persist after returning
p.city = "seattle"
}
</code></pre>
<p>Pointer receiver:</p>
<pre><code>func (p *Place) updateFieldPointer() {
// because p is a pointer to a Place, changes to p
// persist after returning
p.city = "chicago"
}
</code></pre>
<p>Calling the method looks exactly the same for both pointer and value receivers. No special syntax required.</p>
<pre><code>var thePlace Place
thePlace.city = "denver"
thePlace.updateFieldValue()
// thePlace.city is still "denver"
thePlace.updateFieldPointer()
// thePlace.city changed to "chicago"
</code></pre></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传