newbe question regarding the use of anonymous fields, Why do you use them?

xuanbao · · 458 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>I came across this <a href="http://golangtutorials.blogspot.com/2011/06/anonymous-fields-in-structs-like-object.html" rel="nofollow">blog post on anonymous fields</a> </p> <p>I&#39;m a bit confused as to why would want to use an anonymous field as opposed to declaring a name with the type. </p> <p>The example in go</p> <pre><code>package main import &#34;fmt&#34; type Kitchen struct { numOfLamps int } type House struct { Kitchen numOfLamps int } func main() { h := House{Kitchen{10}, 3} //to initialize you have to use composed type name. fmt.Println(&#34;House h has this many rooms:&#34;, h.numOfRooms) //numOfRooms is a field of House fmt.Println(&#34;House h has this many plates:&#34;, h.numOfPlates) //numOfPlates is a field of anonymous field Kitchen, so it can be referred to like a field of House fmt.Println(&#34;The Kitchen contents of this house are:&#34;, h.Kitchen) //we can refer to the embedded struct in its entirety by referring to the name of the struct type } </code></pre> <p>compared with the example in java</p> <pre><code>public class Kitchen { public int numOfPlates; } public class House { public Kitchen kitchen; } //and in main public static void main(String[] args) { House h = new House(); h.kitchen.numOfPlates = 10; //referred as a sub field item. } </code></pre> <hr/>**评论:**<br/><br/>TheMerovius: <pre><p>Because Fields and Methods are being promoted. Thus you can share one implementation between different structs. Say, for example, you have a parser that spits out an AST, with each kind of node being a separate type. All nodes will share a bunch of behavior and data - they all need to carry information of their position, for example. So you can create a <code>Node</code> type, which contains this common behavior and then embed it into the specific nodes to get it &#34;for free&#34;.</p> <blockquote> <p>compared with the example in java</p> </blockquote> <p>I&#39;m not sure what the point is you are trying to make. You can also write the Go-accessor that way, if you prefer: <code>h.Kitchen.numOfPlafes</code>.</p> <p>But yes, accessing common fields isn&#39;t that much of an advantage. It becomes more interesting, when you also take into account methods.</p> <pre><code>type Foo struct { io.ReadCloser SomeMoreStuff int } func main() { f := Foo{os.Stdin, 42} dec := json.NewDecoder(f) // f implements io.Reader, even though it has no explicit method declared // do things } </code></pre> <p>This is probably the most popular use of embedding: You embed a type, so that it implements an interface that you are interested in for free. Often you also use that to overwrite methods with extra behavior:</p> <pre><code>func (f *Foo) Close() error { err := f.ReadCloser.Close() fmt.Println(&#34;Close() = %v&#34;, err) return err } </code></pre></pre>forgiveangel: <pre><p>Ah so the difference between something like </p> <pre><code>type Foo struct { io.ReadCloser SomeMoreStuff int } </code></pre> <p>and</p> <pre><code>type Foo struct { tmp io.ReadCloser SomeMoreStuff int } </code></pre> <p>is just stylistic? </p> <p>I don&#39;t thnk I understand what is happening here either </p> <blockquote> <blockquote> <p>f := Foo{os.Stdin, 42}</p> </blockquote> </blockquote> <p>Can you explain </p> <blockquote> <blockquote> <p>dec := json.NewDecoder(f) // f implements io.Reader, even though it has no explicit method declared Why does f implement io.Reader? Is it because of the anonymous field io.ReadCloser </p> </blockquote> </blockquote> <p>Or if you can direct me to a reading to better understand this.</p></pre>TheMerovius: <pre><blockquote> <p>is just stylistic?</p> </blockquote> <p>No, that is the opposite of what I was saying. When using <em>accessors</em> or in respect to the fields it is just stylistic. But embedding changes the method set of the embedding type: When you embed <code>T1</code> into <code>T2</code>, all methods of <code>T1</code> get promoted to <code>T2</code>. This is relevant because it means you can use <code>T2</code> as any interface, that <code>T1</code> implements.</p> <p>This is what I illustrated with that code: <code>Foo</code> does not itself declare any methods, but the methods of the embedded <code>io.ReadCloser</code> get promoted, so the type <code>Foo</code> gets methods <code>Read</code> and <code>Close</code> and can henceforth be used as an <code>io.Reader</code> or an <code>io.Closer</code> (or an <code>io.ReadCloser</code>) <em>itself</em>.</p> <p>The difference between calling <code>Foo.tmp.Close</code> and calling <code>Foo.Close</code> is aesthetic; but method-promotion is more than just adding syntactic sugar for the call. It actually adds a <code>Close</code> method on <code>Foo</code>, thus changing what interfaces it implements.</p> <p>This is fundamentally different to the java-code or what happens when you add it as a named field.</p></pre>forgiveangel: <pre><p>Whoa... that is really cool, I think I get it. It&#39;s like if there are method that you want to have associated with a specific struct, you can embed a type that contains those method. So it seems almost like a way of better organization. </p></pre>Sythe2o0: <pre><p>The difference is not stylistic.</p> <p>In the former case, you can now call the methods of <code>io.ReadCloser</code> on <code>Foo</code> as well, which also means that <code>Foo</code> satisfies any interfaces those methods enable it to. </p> <p><code>f := Foo{os.Stdin, 42}</code> is creating a new <code>Foo</code>, created with os.Stdin as it&#39;s <code>io.ReadCloser</code> and 42 as it&#39;s <code>SomeMoreStuff</code>.</p> <p><code>f</code> implements io.Reader because it is composed of an <code>io.ReadCloser</code>, which itself implements <code>io.Reader</code>.</p></pre>forgiveangel: <pre><p>is os.Stdin a variable of the os package that you&#39;re typecasting to the type io.ReadCloser?</p></pre>Sythe2o0: <pre><p>That&#39;s one way to think of it, but I think the use of the phrase &#34;typecasting&#34; would be refused by some Go developers.</p></pre>forgiveangel: <pre><p>Ah, I first learned C.</p> <p>Why would you want the variable os.Stdin to be of type io.ReadCloser ? just to have access to the read and close methods from io.ReadCloser?</p></pre>Sythe2o0: <pre><p>So that your function / struct could accept anything that satisfies the <code>io.ReadCloser</code> interface, like a file or a network connection, instead of having to accept os.Stdin.</p></pre>macpla: <pre><p>In Go interfaces are implicitly satisfied. This means that when any function/struct requires an interface, it really says that: &#39;I don&#39;t care about your type as long as you implement my interface&#39;. In jargon people say that Interface defines &#39;contract&#39; and each concrete type which satisfy(implement) this contract (all of it) can be used. In example above io.ReadCloser is an interface from io package which is by itself combined from two other interfaces io.Reader and io.Closer so to satisfy io.ReadCloser contract one needs to provide concrete type which implements two methods: * Read(p []byte) (n int, err error) * Close() error Such concrete example is an os.Stdin instantiation of filehandler from os package. </p></pre>yawboakye: <pre><p>It&#39;s called struct embedding. What happens is that the outer struct inherits (please don&#39;t think in terms of OOP-ish class inheritance; I just mean the word) methods and fields of the embedded struct.</p> <p>A typical example is embedding <code>sync.Mutex</code> in your struct to provide a locking mechanism. Say you have a concurrency-safe cache, you could implement it as</p> <pre><code>type SafeCache struct { sync.RWMutex cache map[string]interface{} } </code></pre></pre>

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

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