How to avoid repetitive code

agolangf · · 464 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>Hello, I am new to Go and I&#39;ve been contributing to a project in Go, and I am stuck at a place where I can&#39;t use a common function to attach metadata to different type of objects with same attributes.</p> <p>Let&#39;s say these are the two structs I have.</p> <pre><code>type ActivityOrganization struct { ID bson.ObjectId `bson:&#34;_id&#34; json:&#34;id&#34;` Type string `bson:&#34;-&#34; json:&#34;type&#34;` URL string `bson:&#34;-&#34; json:&#34;url&#34;` Object1 Organization `bson:&#34;object1&#34; json:&#34;object1&#34;` Object2 *Organization `bson:&#34;object2&#34; json:&#34;object2&#34;` } type ActivityUser struct { ID bson.ObjectId `bson:&#34;_id&#34; json:&#34;id&#34;` Type string `bson:&#34;-&#34; json:&#34;type&#34;` URL string `bson:&#34;-&#34; json:&#34;url&#34;` Object1 User `bson:&#34;object1&#34; json:&#34;object1&#34;` Object2 *User `bson:&#34;object2&#34; json:&#34;object2&#34;` } </code></pre> <p>These are the functions I&#39;m using,</p> <pre><code>func ActivityOrganizationMetadata(ao *common.ActivityOrganization) { ID := ao.ID.Hex() ao.Type = &#34;activity_stream&#34; ao.URL = &#34;/v1/organizations/&#34; + ID + &#34;/activity_stream/&#34; } func ActivityUserMetadata(ao *common.ActivityUser) { ID := ao.ID.Hex() ao.Type = &#34;activity_stream&#34; ao.URL = &#34;/v1/users/&#34; + ID + &#34;/activity_stream/&#34; } </code></pre> <p>Is there anyway in Go where I can use a common function to do this or to make it less repetitive?</p> <hr/>**评论:**<br/><br/>skidooer: <pre><p>Often the question is not &#34;how do I make this specific code less repetitive?&#34; as it is &#34;how can I solve my problem in an idiomatic Go way?&#34; which often does not introduce repetition in the first place. Unfortunately, without knowing anything about the problem trying to be solved, it is difficult to suggest a solution. Especially when you are new to the language, it&#39;s easy to try and solve the problem the same way you would in some other language, rather than how you might approach it in Go specifically.</p> <p>However, given the limited information available: <a href="https://play.golang.org/p/oICjKVBzMx" rel="nofollow">https://play.golang.org/p/oICjKVBzMx</a></p></pre>chmikes: <pre><p>A possible solution is to define a third struct that contains the common fields. You may then define methods for this common base struct.</p> <pre><code> type Activity struct { ID bson.ObjectId Type string URL string } func (a *Activity) Init(obj string, type string) { a.Type = type a.URL = &#34;/v1/&#34;+obj+&#34;/&#34;+a.ID.Hex()+&#34;/&#34;+type+&#34;/&#34; } type ActivityOrganization struct { Activity Object1 ORganization ... } func ActivityOrganizationMetadata(ao *ActivityOrganization) { ao.Init(&#34;organizations&#34;, &#34;activity_stream&#34;) ... } </code></pre> <p>As you see it is possible to implement the good old object oriented paradigm with inheritance in Go. Note that you could call methods of the common base struct on the derived objects.</p></pre>reflectioned: <pre><p>This is exactly what I thought, when I read the question. Maybe you could also embed the type, but that depends on the problem. I personally would always go with the composition approach. Not that much a fan of inheritance ;)</p></pre>forfunc: <pre><p>This is not inheritance. It is composition, go doesn&#39;t support inheritance</p></pre>chmikes: <pre><p>Sorry my bad. The example code I provided is a struct composition. Go doesn&#39;t indeed support inheritance. See <a href="http://spf13.com/post/is-go-object-oriented/" rel="nofollow">http://spf13.com/post/is-go-object-oriented/</a>.</p></pre>neoasterisk: <pre><p>Something that many newcomers are not aware is that you can easily convert between types as long as they have the same fields: </p> <pre><code>package main import ( &#34;fmt&#34; ) type Article struct { ID int Title string } type ArticleRequest struct { ID int Title string } func main() { r := &amp;ArticleRequest{ID: 1, Title: &#34;How to Go&#34;} a := (*Article)(r) // easy conversion in one line! fmt.Printf(&#34;%#v&#34;, a) // prints: &amp;main.Article{ID:1, Title:&#34;How to Go&#34;} } </code></pre> <p>The caveat is that if the types have different struct tags like <code>json:&#34;name&#34;</code> then you can not convert between them. But fear not, in Go 1.8 which will be available in a few days, struct tags are ignored when converting!</p></pre>izuriel: <pre><p>This sounds like an incredibly bad and unsafe thing to do. I would recommend not doing this at all. There are probably astronomically few situations where this is more useful than a safer, less brittle and more readable and clear solution. </p></pre>skidooer: <pre><p>While I tend to agree about it not being the right approach here, I&#39;m left wondering under what scenario it could be unsafe? The compiler will only allow the cast if the memory layout is known to be identical.</p></pre>

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

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