Beginner's question about struct embedding/encapsulation

blov · · 408 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>Hi. As far as I understood, go allows structs that embed another struct to call the methods from the embedded struct as if it were a derived class, like this:</p> <pre><code>type embedded struct { name string value int } func (p *embedded) double() int { return p.value * 2 } type embedding struct { embedded ext bool } func main() { var p = &amp;embedded{&#34;hello&#34;, 1} var d = &amp;embedding{embedded{&#34;world&#34;, 2}, true} println(p.double()) println(d.double(), d.ext) } </code></pre> <p>So the method <code>double()</code> can be called from both <code>p</code> and <code>d</code>. So far, so good. What I don&#39;t understand is why it doesn&#39;t work when an embedding struct is the argument to a function that expects the embedded struct, like this:</p> <pre><code>func printName(p *embedded) { println(p.name) } </code></pre> <p>That function cannot be called from main with <code>printName(d)</code> but requires <code>printName(&amp;d.embedded)</code>. Can&#39;t the compiler infer that? Am I doing something wrong?</p> <hr/>**评论:**<br/><br/>ChristophBerger: <pre><p>Struct embedding provides a shortcut for accessing fields and methods of the embedded struct. <code>func printName</code>, on the other hand, expects an <code>embedded</code> but <code>printName(d)</code> passes an <code>embedding</code> instead. This is a classic type mismatch. There is no field or method access happening in <code>printName(d)</code>, so the shortcut rules do not apply. </p> <p>This should work:</p> <pre><code>func printName(name string) { println(name) } printName(p.name) printName(d.name) // field access shortcut </code></pre> <p>Edit: added the p.name line</p></pre>anotherdonald: <pre><p>I know that works, but it seems to me the inference embedding-&gt;embedded could be the same for both the method and the function, since essentially the method argument is nothing but a parameter.</p></pre>TheMerovius: <pre><p>Embedding isn&#39;t subtyping and that&#39;s intentional. Your <code>embedding</code> doesn&#39;t <em>become</em> an <code>embedded</code>, it <em>embeds</em> it. Yes, of course go <em>could</em> make embedding be subtyping, but it discourages what some of the go team call &#34;programming types&#34;, which is what happens naturally in a world where subtyping exist (see java, for an example, where &#34;java coding&#34; in general means &#34;building elaborated type hierarchies that make it impossible to understand what is actually going on&#34;). </p></pre>anotherdonald: <pre><p>Thanks.</p> <p>But as there is no overloading, there can only be one function with that specific name (printName in my case), which renders the potential confusion rather limited, IMO. And the same argument would also hold against struct methods: I could just as well write <code>d.embedded.double()</code>.</p> <p>But if you say it&#39;s intentional, I&#39;ll have to live with it.</p></pre>TheMerovius: <pre><p>I didn&#39;t talk about &#34;confusion&#34;. And if Methods weren&#39;t promoted, it would limit the use of embedding for interface implementation. But note also, that the method will still be called on an <code>embedded</code>, not an <code>embedding</code>, so it&#39;s not really like an <code>embedding</code> would become an <code>embedded</code> in that sense.</p></pre>anotherdonald: <pre><blockquote> <p>I didn&#39;t talk about &#34;confusion&#34;.</p> </blockquote> <p>I took your statement &#34;impossible to understand what is actually going on&#34; to mean that in Java it can be hard to know what&#39;s happening by just reading the code since there can so many candidates for a function or method call, and I can&#39;t see that happen with automatic de-embedding.</p> <blockquote> <p>But note also, that the method will still be called on an embedded, not an embedding, so it&#39;s not really like an embedding would become an embedded in that sense.</p> </blockquote> <p>Sure, I wasn&#39;t expecting anything else. I was just hoping the compiler would automatically insert .embedded for me.</p></pre>joncalhoun: <pre><p>If you really just care about &#34;does it have access to x&#34; then you probably want to use interfaces, but this means you need to write a method to access name. eg: <a href="https://play.golang.org/p/TmigbUQKw5" rel="nofollow">https://play.golang.org/p/TmigbUQKw5</a></p></pre>knotdjb: <pre><p>You want to pass <code>&amp;d.embedded</code> <a href="https://play.golang.org/p/ke_T1SA0j7" rel="nofollow">like so</a>.</p> <blockquote> <p>Can&#39;t the compiler infer that?</p> </blockquote> <p>I assume it probably could but this violates the notion of strong typing which is a feature of Go.</p></pre>Tikiatua: <pre><p>You should create an interface that defines any methods you want to call on the struct passed to the print function.</p> <p>You can then pass your struct with the embedded struct into the function.</p> <p>The most basic imterface would be interface{}.</p></pre>NeverUse-YouPromised: <pre><p>structs can embed interfaces too. So you could do something like</p> <pre><code>type NameValuer interface { Name() string Value() int } func (p *embedded) Name() string { return name } func (p *embedded) Value() int { return value } type embedding struct { NameValuer ext bool } func printName(p NameValuer) { println(p.Name()) } </code></pre> <p>And now <code>printname(d)</code> works. However, I don&#39;t recommend doing so as it&#39;s probably not idiomatic Go and confuses the roles of structs and interfaces. The typical use of interface embedding is to override methods of the parent; for example, <code>sort.Reverse</code> embeds another <code>sort.Interface</code> and overrides its <code>Less</code> method to compare the operands in reverse.</p></pre>anotherdonald: <pre><p>Yes, thanks. I know about interfaces, but it seemed so obvious to me that if both types can be used in the context of one function call, that they can also be used in the context of another. I&#39;ve given up on this approach for the moment, and made a big &#34;union&#34; struct with a field that specifies the type. Ugly, but easy on the calling functions.</p></pre>

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

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