[Noob]Function parameters are not pass-by-reference, but what would pass-by-reference look like?

xuanbao · · 675 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>From the official FAQ:</p> <blockquote> <p>As in all languages in the C family, everything in Go is passed by value. That is, a function always gets a copy of the thing being passed, as if there were an assignment statement assigning the value to the parameter. For instance, passing an int value to a function makes a copy of the int, and passing a pointer value makes a copy of the pointer, but not the data it points to. (See a later section for a discussion of how this affects method receivers.)</p> </blockquote> <p>I thought passing a pointer <em>is</em> passing by reference but it&#39;s not. So would pass by reference work? I believe it would be passing the pointer and using that same pointer instead of making a copy. If this is true then would the result of passing a pointer value to a function vs passing a reference to a function be the same? I know Go can&#39;t do this. This is more of a general conceptual question.</p> <hr/>**评论:**<br/><br/>jerf: <pre><p>From a modern programming language perspective, it can be difficult to understand what &#34;pass-by-reference&#34; or &#34;pass-by-name&#34; truly means, because every modern language is pass-by-value. That is, there is some sort of distinct &#34;function call&#34;, which receives copies of arguments from the caller, proceeds to do its business on its copies, and then returns, destroying its copies in the process.</p> <p>It&#39;s easy to get confused by the fact that one of the things that can be passed are references/pointers, so if a function gets passed an *int and uses it to modify something, it may look like there was something &#34;passed by reference&#34;. But in fact under the hood, while the function is running, there is two places in memory that have a pointer to the int in question, and no matter what the called function does, it can&#39;t change the original pointer. (For that, you could pass a pointer to a pointer, but then the called function can&#39;t change <em>that</em>. And so on.)</p> <p>There&#39;s a few languages that still simulate this at the language level, where there&#39;s a hidden pointer not exposed to you, the programmer, that is passed in, but there&#39;s still a copy made of the pointer. Then it looks as if you can have:</p> <pre><code>func Caller() { i := 1 Incr(i) fmt.Println(i) } func Incr(i int) { i += 1 } </code></pre> <p>and have Caller end up printing 2, but there&#39;s still a pointer copy.</p> <p>The <em>real</em> &#34;pass-by-name&#34; or &#34;pass-by-reference&#34; languages, though, had very different mechanisms for calling a function that didn&#39;t involve making copies of anything. Forth, for instance, had a stack that all functions pulled from, so if you had a stack with <code>[1, 2, 3, 4]</code> on it, and called the <code>+</code> function/operator/word, the result is a stack with <code>[1, 2, 7]</code> in it. No copy of the 3 or 4 was made; the + operator directly operates on the values in the stack, and directly wrote the value back on to the stack, popping the bottom one off (that is, after the 7 is probably still a 4 in memory, to be overwritten the next time the stack grows again).</p> <p>Back in the days of constrained resources, this could be a major advantage for Forth vs. trying to port a language that does copying on every function call when every byte is precious. That&#39;s the real alternative to the modern world of &#34;pass-by-value`, but it&#39;s almost impossible to point at a modern language currently in use that works that way. Other languages existed that had things that looked like a conventional function call, but hooked up the called function to operate directly on the original input unconditionally, again with no copy made.</p> <p>One of the ways in which your CPU is secretly not really a &#34;general purpose computer&#34; but actually the distant descendant of &#34;a C execution unit&#34; is the way CPUs have developed various fast ways to quickly copy a small amount of parameters into a function without actually hitting RAM, by fiddling with registers and how they are represented, to minimize the penalties associated with the amount of copying this entails. In an alternate universe where Forth won out as the base systems language, the C-like languages would be mocked by the heavy-duty systems programmers as being slow because of all of its copying it has to do, and its inefficient use of the more powerful and flexible stack that processors would be equipped with to run Forth more quickly. Instead we live in a world where Forth has to do some workarounds to make its stack ideas work efficiently and it doesn&#39;t necessarily get to take advantage of all the speed hacks to make C work fast.</p></pre>KeyYam: <pre><p>whoah, thanks. I had to read this a few times but it makes more sense to me now. Quick question: when you say &#39;The real &#34;pass-by-name&#34; or &#34;pass-by-value&#34; languages, though..&#39; did you actually mean to say &#39;The real &#34;pass-by-name&#34; or &#34;pass-by-reference&#34;? </p></pre>jerf: <pre><p>Yes, thank you. Fixed.</p></pre>a_t-2: <pre><p>a pointer is a value, it&#39;s an address. Case point : you can change the value of a pointer.</p> <p>you cannot change what references a reference type.</p> <p>Go actually has kinda reference types : slices.</p> <p><a href="https://play.golang.org/p/RD6dlboEIpx" rel="nofollow">https://play.golang.org/p/RD6dlboEIpx</a></p> <p>C++ has reference types so this FAQ is false.</p> <p><a href="https://en.wikipedia.org/wiki/Reference_(C%2B%2B)" rel="nofollow">https://en.wikipedia.org/wiki/Reference_(C%2B%2B)</a></p></pre>tv64738: <pre><blockquote> <p>Go actually has kinda reference types : slices.</p> </blockquote> <p>Slices are not refences, they just point to an array that you can mutate.</p> <p><a href="https://play.golang.org/p/HNuZbxb0rYx" rel="nofollow">https://play.golang.org/p/HNuZbxb0rYx</a><br/> <a href="https://blog.golang.org/slices" rel="nofollow">https://blog.golang.org/slices</a></p> <p>If you want to argue that Go sort of has reference types, make your argument with map. A map is a pointer, but very early on they decided typing <code>*map[A]B</code> everywhere was awkward, and the language forbid derefencing it anyway, so they just made the asterisk not needed.</p></pre>a_t-2: <pre><blockquote> <p>Slices are not refences, they just point to an array that you can mutate.</p> </blockquote> <p>Some other languages chose copy on pass when it comes to arrays. Anyway the choice go made is highy debatable.</p></pre>tv64738: <pre><p>The choice Go made for arrays is pass-by-value.</p></pre>kostix: <pre><p>While slices are not references, they have reference semantics, since assigning a value of a slice type to another variable creates another place referencing the same backing storage array.</p></pre>tv64738: <pre><p>Calling slices reference types is confusing because each slice variable has its own copy of len and cap even if they point to the same underlying array. <a href="https://blog.golang.org/slices" rel="nofollow">https://blog.golang.org/slices</a></p></pre>nagai: <pre><p>Pass by value creates a local copy of the argument, whereas pass by reference creates an alias of the actual argument. Pointers are no different, they are just variables whose value is the address of some other value. I.e., in go passing down a pointer is essentially just passing down a copy of that address.</p></pre>govision: <pre><p>Sorry but I just love these blogs! </p> <p><a href="https://blog.golang.org/slices" rel="nofollow">https://blog.golang.org/slices</a></p> <p><a href="https://blog.golang.org/go-slices-usage-and-internals" rel="nofollow">https://blog.golang.org/go-slices-usage-and-internals</a></p> <p>They make me want to drop everything and study code. </p> <p>And the one that really explains it! <a href="https://research.swtch.com/godata" rel="nofollow">https://research.swtch.com/godata</a></p> <p>And of course bill&#39;s easier explanation. <a href="https://www.ardanlabs.com/blog/2013/08/understanding-slices-in-go-programming.html" rel="nofollow">https://www.ardanlabs.com/blog/2013/08/understanding-slices-in-go-programming.html</a></p> <p>And just cause <a href="https://nanxiao.gitbooks.io/golang-101-hacks/content/posts/the-internals-of-slice.html" rel="nofollow">https://nanxiao.gitbooks.io/golang-101-hacks/content/posts/the-internals-of-slice.html</a></p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

675 次点击  
加入收藏 微博
0 回复
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传