Passing slices by reference

polaris · · 470 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>I was replying to a post by <a href="/u/PedanticGeorge">/u/PedanticGeorge</a> regarding concurrency and the passing of slices by reference vs. value only to find the post and many of his comments deleted while writing my reply.</p> <p>I wanted to post my findings anyway for two reasons - to help me understand arrays and slices; and in case it&#39;s of any use to others.</p> <p>If I understand things correctly, slices can be passed by value or by reference (using a pointer). The underlying arrays for those slices are <em>always</em> passed by reference implicitly.</p> <p>This is something that caught me out recently so I&#39;ve put an example together on the playground. Note that whether you pass the slice by value or by reference, the backing array is modified when calling append(). I imagine that dealing purely with slices would simplify things greatly as you are no longer concerned with the underlying array. </p> <p><a href="https://play.golang.org/p/xXyT1yYoPk">https://play.golang.org/p/xXyT1yYoPk</a></p> <p>I&#39;d be grateful for any feedback/corrections.</p> <hr/>**评论:**<br/><br/>YEPHENAS: <pre><p>This</p> <pre><code>func f(s []string) {} </code></pre> <p>is equivalent to</p> <pre><code>func f(ptr *string, len, cap int) {} </code></pre> <p>or</p> <pre><code>type stringSlice { ptr *string // points to an element within an array of strings len, cap int } func f(s stringSlice) {} </code></pre></pre>dchapes: <pre><blockquote> <p>passing of slices by reference vs. value</p> </blockquote> <p>There is no passing by reference in Go, everything is passed by value. You are passing pointer <strong>values</strong> not references.</p> <p>Words and terminology matter and using incorrect terminology just confuses things.</p></pre>goomba_gibbon: <pre><p>I get that *int and int are distinct types in Go. How is passing a pointer not a reference? Is this only a semantic difference or something more?</p></pre>snowzach: <pre><p>Yah, passing a pointer to something is passing by reference. Slices in go are inherently references though so you don&#39;t pass a pointer to a slice, you just pass the slice and it&#39;s like you passed a reference to it.</p></pre>softwaregav: <pre><p>Slices in go are inherently references to the underlying array, not themselves. If you want to pass a slice by reference, you still have to pass a pointer to it.</p></pre>goomba_gibbon: <pre><p>I think this is only partially true. If you pass a slice to a function and alter that slice (by setting slice[0] = something) then the underlying array is also modified. That means you don&#39;t need to pass a pointer in that case.</p> <p><a href="/u/ChristophBerger" rel="nofollow">/u/ChristophBerger</a> demonstrates this behaviour here - <a href="https://play.golang.org/p/Gs3KRf47v8" rel="nofollow">https://play.golang.org/p/Gs3KRf47v8</a></p></pre>softwaregav: <pre><blockquote> <p>Slices in go are inherently references to the underlying array, not themselves.</p> </blockquote> <p>So, if you copy a slice, you still have a pointer to the same underlying array. Because of this, there doesn&#39;t really seem to be much of an advantage to passing the pointer of a slice, but I believe the difference is still there.</p></pre>goomba_gibbon: <pre><p>Thanks for the response.</p> <blockquote> <p>Slices in go are inherently references though so you don&#39;t pass a pointer to a slice, you just pass the slice and it&#39;s like you passed a reference to it.</p> </blockquote> <p>Is this true? You can&#39;t modify the original slice in a function without passing a pointer to it, can you? See the first two parts of the playground example.</p></pre>FUZxxl: <pre><p>You can easily understand slice if you know that a slice is just a structure containg a pointer to some memory, a length and a capacity. Passing a slice makes a copy of that structure, but the pointer still refers to the same chunk of memory.</p></pre>ChristophBerger: <pre><blockquote> <p>You can&#39;t modify the original slice in a function without passing a pointer to it, can you?</p> </blockquote> <p>You can modify the <em>contents</em> of a slice passed by value. See this <a href="https://play.golang.org/p/Gs3KRf47v8" rel="nofollow">modified playground code</a>. I added two functions, sliceByVal2 and sliceByRef2, that modify the original slice.</p> <p>The point is, the <em>slice header</em> is a struct that contains a pointer to the slice content and the length of the slice. The header is passed by value (as everything in Go), but the pointer within the header still points to the original slice. That&#39;s why sliceByVal2() can modify the original slice.</p> <p><code>append()</code> <a href="https://golang.org/pkg/builtin/#append" rel="nofollow">returns a new slice</a> if the original slice has not enough capacity for appending more values. In this case, <code>append()</code> modifies the slice header that is just a local copy of the original slice header and is discarded when the function call returns. This is why the original sliceByVal() left the original slice untouched.</p></pre>goomba_gibbon: <pre><p>This is a great explanation. Thank you.</p></pre>0xjnml: <pre><p>A reference cannot be dereferenced. A pointer can.</p></pre>goomba_gibbon: <pre><p>Thanks. I still think a pointer is a reference but it&#39;s good to be explicit to avoid confusion.</p></pre>itsmontoya: <pre><p>Passing a pointer and passing by reference is the same thing. Don&#39;t get caught up arguing over semantics</p></pre>

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

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