is context.Context() pass-by-value?

agolangf · · 531 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>I see a lot of code has &#34;ctx context.Context()&#34; as parameter. e.g., <a href="https://github.com/bborbe/cron/blob/20d491ed207180aacf635b2006c0c293fd2ab9e1/cron.go#L6" rel="nofollow">https://github.com/bborbe/cron/blob/20d491ed207180aacf635b2006c0c293fd2ab9e1/cron.go#L6</a></p> <p>If this is pass-by-value, isn&#39;t it not efficient?</p> <hr/>**评论:**<br/><br/>Sythe2o0: <pre><p>Everything in Go is pass by value. What is your efficiency concern?</p></pre>drvd: <pre><p>Yes of course as everything in Go is passed by values. Even pointers are passed by value.</p></pre>: <pre><p>[deleted]</p></pre>Sythe2o0: <pre><p>That&#39;s not a reference. A reference is not a pointer, a reference is a more abstract concept. In Go, pointers are passed by value as literal pointers as opposed to as references.</p> <p>If Go arbitrarily changed the things you passed around so that they became pointers when they were not, that would indicate pass by reference behavior. Go doesn&#39;t do this, it copies whatever you send through (which in this case is a pointer)</p></pre>jerf: <pre><p>Here&#39;s what it comes down to: All programming language terms only have <em>concrete, defined</em> meanings within a given language context.</p> <p>There is no universal definition of &#34;pass by reference&#34;. There are more variations on the theme than there are official names for it, since there&#39;s 2 or 3 names and probably dozens of variations on the theme.</p> <p>&#34;But jerf, surely something like pass-by-value is unambiguous?&#34; No, it isn&#39;t. In some languages, if you &#34;pass-by-value&#34; anything you can get to by the original value can&#39;t be changed. In a lot of other languages, including Go, if you pass a struct by value that has a pointer in it, you can still follow that pointer and modify something that will be visible to the original caller. Some languages have complicated concepts of &#34;const&#34;ness in them for which &#34;pass by value&#34; is simply inadequate to explain the situation. In immutable languages, you &#34;pass by value&#34; in effect even though under the hood it may be implemented via passing a pointer!</p> <p>In Go, as with many languages, everything is &#34;pass-by-value&#34; making the term rather useless (a term is only useful if it distinguishes between at least two cases), so the relevant question is whether you&#39;re passing in a pointer or not.</p> <p>Incidentally, on the topic of how no term is universally defined, I would <em>generally</em> consider the distinguishing characteristic of a pointer vs. a reference that you can do pointer arithmetic on the pointer. However, while Go has &#34;pointers&#34;, it doesn&#39;t have &#34;pointer arithmetic&#34;. But I still call them &#34;pointers&#34;, because that&#39;s what the language calls them and I&#39;m relaxed about the fact that I have an opinion about the &#34;general&#34; meaning of a term that a particular language/language community disagrees with, because that happens in every community for nearly every term.</p> <p>Others would say the distinguishing characteristic of a reference is that you can transparently change the original caller&#39;s value and you don&#39;t see a &#34;pointer&#34; involved, but there&#39;s really no meaningful difference I know between a &#34;reference&#34; to an int in such a language and a &#34;pointer&#34; to it in Go, except the terminology and how transparent the syntax may make it.</p></pre>Kraigius: <pre><p>Jerf, your comment is the only comment that made any sense in this thread. Thank you.</p> <p>I was very confused, why? From my experience/background outside of Go &#34;passing by reference&#34; is when you do two of the same thing:</p> <ol> <li><p>Pass a pointer to a function for memory optimization so it doesn&#39;t copy the full object.</p></li> <li><p>Mutability: Pass your parameter to a function so that any modification happening inside the function are kept when the function return.</p></li> </ol> <p>I&#39;m well aware of the doctrine that Go is all &#34;pass by value&#34; (except for Slice, Maps...) but I know I could do the above two things in Go. I went to that thread hoping to get any clarification and everyone seemingly contradicted each others and used different terminology (pass by pointer??).</p> <p>Then you came along saying that &#34;pass-by-reference&#34; means jack shit and it&#39;s just languages coming up with their own rules and jargon.</p></pre>WintyBadass: <pre><p>And how do you think references are implemented in programming languages? With pointers.</p></pre>Sythe2o0: <pre><p>Sometimes.</p></pre>WintyBadass: <pre><p>Ok than how else could it be done?</p></pre>Sythe2o0: <pre><p>A reference is a sort of interface, you could imagine it in go as <code>type Reference interface { Dereference() Value }</code>. So anything that satisfies that could be a reference. </p> <p>If you wanted, you could have them be array indices or map keys, for example. Usually you&#39;d use pointers for efficiency.</p></pre>WintyBadass: <pre><p>I know what is reference. I&#39;m talking about how are references implemented in programming languages (and Go). Always it&#39;s pointer or some variations to it.</p></pre>Sythe2o0: <pre><p>That&#39;s not true. If you wanted to implement a reference in whitespace, for example, you&#39;d need it to be the number of stack pops needed to reach the desired value.</p></pre>WintyBadass: <pre><p>I mean implementation of the language. How do runtimes of Go, Java, and so one do it? To what assembly are references in C++ translated to?</p></pre>drvd: <pre><blockquote> <p>[...] passing the address of a pointer by value is called passing by reference.</p> </blockquote> <p>No, not at all.</p> <p>Some languages do have actual references some don&#39;t. Go is in the &#34;don&#39;t&#34; camp. Passing a pointer to an A is not &#34;pass by reference&#34;. Passing a pointer to a pointer to A is even less &#34;pass by reference&#34;.</p></pre>icholy: <pre><blockquote> <p>Passing a pointer to an A is not &#34;pass by reference&#34;.</p> </blockquote> <p>C&#39;mon ... a pointer is a reference. Quit being pedantic.</p></pre>drvd: <pre><p>Well, references and pointers to values are different things and a lot of confusion stems from thinking mixing up these two concepts. Being precise in your language is helpful in reasoning about stuff. When you reason about a physical system you do not mix up power and energy.</p></pre>tv64738: <pre><p>In that case, an array index is a reference too, and words mean nothing.</p></pre>tv64738: <pre><p><a href="https://golang.org/pkg/context/#Context" rel="nofollow">context.Context</a> is an interface. It&#39;s size is two pointers. Copying up to 16 bytes shouldn&#39;t give you vague terrors like that.</p></pre>TheMerovius: <pre><p><code>context</code> is actually a pretty nifty and efficient design <em>where it matters</em>. Basically, you are passing around const-pointers (the pointer part comes from the fact that you are using an interface, which uses pointers under the hood. The const-part comes from the fact that the interface doesn&#39;t let you mutate the values), giving you an immutable linked list. But what&#39;s more, it&#39;s a tree - forked contexts (e.g. when spawning a new goroutine which then creates its own child-contexts) safely share all the memory with their parent.</p> <p>The important consequence of all of this is, that <code>context</code> <em>doesn&#39;t require synchronization</em> to do it&#39;s thing in a concurrent program, while still sharing most of it&#39;s memory. There are channels involved in cancellation and the like, but the data-structure itself is totally concurrency safe.</p> <p>It&#39;s a pretty cool design, honestly :)</p></pre>hanmunjae: <pre><p>Since there is no <code>*</code> in front of the type, it is passed by value.</p> <pre><code>func foo(ctx context.Context) // Pass by value func foo(ctx *context.Context) // Pass by pointer </code></pre> <p>However, <code>context.Context</code> is an interface. All interfaces are implemented with two machine-size (i.e., 64-bit on most machines) words, so they are small values and in most cases it is acceptable to pass them by value.</p> <p>Source: <a href="https://research.swtch.com/interfaces" rel="nofollow">https://research.swtch.com/interfaces</a></p></pre>tv64738: <pre><p>Everything is passed by value. That value may be a pointer.</p></pre>marksteve4: <pre><p>Hmm. I got totally opposite answers</p></pre>wjkohnen: <pre><p>Even if you disagree that passing pointers by value wasn&#39;t passing by value, note that context.Context is even <a href="https://github.com/golang/go/blob/2d69e9e259ec0f5d5fbeb3498fbd9fed135fe869/src/context/context.go#L169" rel="nofollow">an integer</a>, not a pointer. </p> <p>But you should grasp the idea that passing pointers by value is in fact not passing by reference if you want to prepare for subleties when passing maps, slices ... and other types like ctx for that matter.</p> <p>What the difference of an <code>int</code> to a pointer means in the context of passing values is left as an exercise to the reader. ;)</p> <p>/e: The above argument has a flaw. It doesn&#39;t render the point moot though. Have fun. </p></pre>ariacode: <pre><p><code>context.TODO()</code> and <code>context.Background()</code> return pointers to said type.</p></pre>wjkohnen: <pre><p>You receive full points. :)</p> <p>Right after I wrote my comment, I realized that <code>context.Background()</code> returns <code>new(emptyCtx)</code> which creates a pointer to a new zero valued <code>int</code>. The only reason this is done (instead of using a <code>struct{}{}</code>; or a pointer to that) is to make the effective symbol (the value doesn&#39;t matter) distinct. </p> <p>In any case the width of the passed value is the same and adding another indirection is pointless, no pun intended.</p></pre>dchapes: <pre><blockquote> <p>note that context.Context is even <a href="https://github.com/golang/go/blob/2d69e9e259ec0f5d5fbeb3498fbd9fed135fe869/src/context/context.go#L169" rel="nofollow">an integer</a>, not a pointer.</p> </blockquote> <p>This is incorrect as stated. <code>emptyCtx</code>, which you link to, is an <code>int</code>. But <code>emptyCtx</code> does not implement <code>context.Context</code>, <code>*emptyCtx</code> does. Further that underlying type is only used for <code>context.Background</code> and <code>context.TODO</code>.</p> <p>Other implementations of <code>context.Context</code> include <a href="https://github.com/golang/go/blob/2d69e9e259ec0f5d5fbeb3498fbd9fed135fe869/src/context/context.go#L316" rel="nofollow"><code>*cancelCtx</code></a> (created by <code>context.WithContext</code> and <code>context.WithDeadline</code>), <a href="https://github.com/golang/go/blob/2d69e9e259ec0f5d5fbeb3498fbd9fed135fe869/src/context/context.go#L411" rel="nofollow"><code>*timerCtx</code></a> (created by <code>context.WithDeadline</code>), and <a href="https://github.com/golang/go/blob/2d69e9e259ec0f5d5fbeb3498fbd9fed135fe869/src/context/context.go#L479" rel="nofollow"><code>*valueCtx</code></a> (created by <code>context.WithValue</code>).</p> <p>So everything in the context package that implements <code>context.Context</code> happens to be a pointer. But that&#39;s an implementation detail.</p> <p>The OP appears to be asking why people are using <code>ctx context.Context</code> as arguments instead of <code>ctx *context.Context</code> and the reason for that has nothing to do with implementation details of any specific implementer of <code>context.Context</code> being a pointer or not. It&#39;s simply because it&#39;s an interface and you very very rarely ever want to use a pointer to an interface.</p></pre>ariacode: <pre><p>the people saying &#34;everything is pass by value&#34; are being obtuse - they know or should know what you mean.</p> <p>Again, look at the <code>context</code> package. Many if not all of the constructors return pointers that implement <code>context.Context</code>.</p></pre>Sythe2o0: <pre><p>Try telling someone that pass by reference and using pointers are equivalent in a language that actually has references as separate types from pointers.</p></pre>ariacode: <pre><p>Given the context (go), I think it was pretty obvious that he meant passing a pointer vs a non-pointer value.</p></pre>Sythe2o0: <pre><p>Then you should had answered that Context is an interface, and interfaces are implemented to be small values?</p></pre>ariacode: <pre><p>I... <a href="https://www.reddit.com/r/golang/comments/6zkzwu/is_contextcontext_passbyvalue/dmw2n87/" rel="nofollow">did</a>. It was the first response in this thread.</p></pre>Sythe2o0: <pre><p>That&#39;s not saying any of the things you should have said. It is pass by value, interfaces are values, and interfaces are small. &#34;Read the package&#34; is useless advice here, nothing about the passing mechanics in Go or about interface size will be learned from doing that.</p></pre>ariacode: <pre><p>lol ok dude.</p> <p>&#34;Yes of course as everything in Go is passed by values&#34; is totally more helpful.</p> <p>whatever.</p></pre>Sythe2o0: <pre><p>I didn&#39;t assume what the efficiency concern was and instead asked for clarification. You did.</p></pre>ariacode: <pre><p>It&#39;s not necessarily pass-by-value - <code>context.Context</code> is an interface. Read through the <code>context</code> package.</p></pre>

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

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