How would you refactor this in Go?

blov · · 659 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p><a href="https://gist.github.com/anonymous/b6babbec57fc0d626fad">Here</a> are two functions that do the same thing, but on two different types. This seems overly repetitive, and I&#39;d like to refactor it into a single method, but am unsure of the idiomatic Go way. Would it be to use interface{} and cast, just leave it as two methods, or something else? </p> <hr/>**评论:**<br/><br/>skidooer: <pre><p>Without knowing more about your application, here is one approach:</p> <pre><code>// TODO update Post and Page to conform to the interface. type sanitizer interface { GetRawContent() []byte SetSafeContent(string) } func fetch(c appengine.Context, q *datastore.Query, items []sanitizer) { if _, err := q.GetAll(c, &amp;items); err != nil { // TODO this should go to the log instead fmt.Println(&#34;FAILURE!!!!!!&#34;) } policy := bluemonday.UCGPolicy() for _, p := range x { parsed := blackfriday.MardownCommon(p.GetRawContent()) html := policy.SanitizeBytes(parsed) p.SetSafeContent(template.HTML(html)) } } </code></pre></pre>bitcycle: <pre><ol> <li><p>The return type indicates that there is at least one code path where an error would be returned. I would expect them both to return if <code>GetAll</code> failed, but neither do. </p></li> <li><p>Use an interface to provide <code>GetRawContent() []byte</code> and <code>SetSafeContent(string)</code> just like in <a href="/u/skidooer">/u/skidooer</a> &#39;s answer. Note, he updated the method name to use a setter method instead of just <code>SafeContent</code> -- which only works if you own the definition in your app for <code>Post</code> and <code>Page</code>.</p></li> <li><p>Add at least a comment explaining what Bluemonday UCG Policies are -- because obscure acronyms from third party libs suck most of the time, or refer to the Bluemonday comment in the <code>policy.go</code> source <a href="https://github.com/microcosm-cc/bluemonday/blob/1f0bc57c5484fb9207c08d5ed7475feaea9e3002/policy.go#L38">here</a>. In addition, you might add a <code>SECURITY.md</code> file to your project outlining how using Bluemonday (and potentially other security-minded libraries) will ensure the safety and security of the application.</p></li> </ol></pre>kromem: <pre><p>You can very easily take control of an externally defined type by embedding it into a locally defined type and overriding/adding the desired methods. </p></pre>bitcycle: <pre><p>Examples?</p></pre>jshen: <pre><p>Thanks for the feedback. Regarding point 1, his is incomplete code I am actively working on. There will be a code path where an error is returned, but I should have cleaned it up before posting it.</p></pre>legec: <pre><p>Is there any point in caching the SafeContent right here ?</p> <pre><code>type content string func (ctnt content) Safe() template.HTML { parsed_content := blackfriday.MarkdownCommon([]byte(ctnt)) html := bluemonday.UGCPolicy().SanitizeBytes(parsed_content) return template.HTML(html) } type Post struct { ID int Content content } type Page struct { ID int Content content } // post.Content.Safe() // page.Content.Safe() </code></pre> <p>You would have to check how this interacts with datastore.</p></pre>gdey: <pre><p>Yeah, I would pull it out and define an interface for it. <a href="http://play.golang.org/p/7wm1l8ZuMl" rel="nofollow">http://play.golang.org/p/7wm1l8ZuMl</a></p> <p>I would not pull out the the GetAll calls.</p></pre>jshen: <pre><p>Yeah, that works. I guess that still feels repetitive to me coming from dynamic languages since I&#39;ll end up making a fetchXXX method for every new type. I&#39;d just have a single generic fetch method in ruby, or in a language with generics. </p></pre>tagesticket: <pre><p>You could do something similar to the sort package. Here&#39;s a sample: <a href="http://play.golang.org/p/dNsxw7KasV" rel="nofollow">http://play.golang.org/p/dNsxw7KasV</a></p></pre>earthboundkid: <pre><p>The core of the two for-loops are the same. That should be pulled out into its own function. </p></pre>G0T0: <pre><p>I imagine all of:</p> <pre><code>_, err := q.GetAll(c, &amp;post) if err != nil { fmt.Println(&#34;FAILURE!!!!!!&#34;) } for i, p := range posts { parsed_content := blackfriday.MarkdownCommon([]byte(p.Content)) html := bluemonday.UGCPolicy().SanitizeBytes(parsed_content) p.SafeContent = template.HTML(html) posts[i] = p } </code></pre> <p>can be pulled out.</p></pre>

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

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