How do i use the interface type in method arguments?

agolangf · · 352 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>The following does not work, how can this be fixed?</p> <pre><code>package main import &#34;fmt&#34; import &#34;math&#34; type V3 struct { x, y, z float64 } func (a V3) dot(b V3) float64 { return a.x*b.x + a.y*b.y + a.z*b.z } func (a V3) sub(b V3) V3 { return V3{a.x - b.x, a.y - b.y, a.z - b.z} } type R3 interface { dot(o R3) float64 sub(o R3) R3 } func dist(a, b R3) float64 { d := a.sub(b) return math.Sqrt(d.dot(d)) } func main() { a := V3{1, 2, 3} b := V3{4, 5, 6} fmt.Println(dist(a, b)) // error: V3 implements &#34;dot(V3) float64&#34; and not &#34;dot(R3) float64&#34; } </code></pre> <p>Obviously the methods in R3 can not be fixed to type V3, but neither can the methods on V3 use R3 as argument type.</p> <hr/>**评论:**<br/><br/>jerf: <pre><p>Types must match exactly. You must implement the dot with signature</p> <pre><code>func (a V3) dot(bIn R3) float64 { b := bIn.(V3) return a.x*b.x + a.y*b.y + a.z*b.z } </code></pre> <p>And that will panic if you pass in a parameter that is not a V3.</p> <p>This is right where Go&#39;s lack of generics hurts the worst, IMHO. If this is the thing you are primarily intending to use Go with, rather than just something you&#39;re playing around with, well, it&#39;s all up to you of course but I&#39;d take this as a sign of a real characteristic of Go.</p></pre>BromoL: <pre><p>Ok, thanks. That&#39;s what I already suspected. But</p> <pre><code>func (a V3) dot(bIn R3) float64 </code></pre> <p>isn&#39;t a solution at all, because there might be other interfaces V3 needs to be compatible with.</p></pre>ChristophBerger: <pre><blockquote> <p>there might be other interfaces V3 needs to be compatible with.</p> </blockquote> <p>This is no problem. As long as V3 implements R3, it can also implement other interfaces as well and still be a valid argument to <code>dot()</code>.</p></pre>BromoL: <pre><p>Ok, now i have</p> <pre><code>package main import &#34;fmt&#34; import &#34;math&#34; type V3 struct { x, y, z float64 } type V2 struct { x, y float64 } func (a V3) dot(bin interface{}) float64 { b := bin.(V3) return a.x*b.x + a.y*b.y + a.z*b.z } func (a V3) sub(bin interface{}) interface{} { b := bin.(V3) return V3{a.x - b.x, a.y - b.y, a.z - b.z} } func (a V2) dot(bin interface{}) float64 { b := bin.(V2) return a.x*b.x + a.y*b.y } func (a V2) sub(bin interface{}) interface{} { b := bin.(V2) return V2{a.x - b.x, a.y - b.y} } type VectorSpace interface { dot(o interface{}) float64 sub(o interface{}) interface{} } func dist(a, b VectorSpace) float64 { d := a.sub(b).(VectorSpace) return math.Sqrt(d.dot(d)) } func main() { a := V3{1, 2, 3} b := V3{4, 5, 6} fmt.Println(dist(a, b)) c := V2{7, 8} d := V2{9, 10} fmt.Println(dist(c, d)) var e V2 = c.sub(d) // :( has type interface{} fmt.Println(e) } </code></pre> <p>Now V3 does not have to know about the interface VectorSpace, but this prevents the natural usage of sub()</p></pre>ChristophBerger: <pre><p>Why did you switch from <code>R3</code> to <code>interface{}</code>? </p> <p>And if you want to avoid runtime panics, I suggest using the &#34;comma, ok&#34; idiom.</p></pre>BromoL: <pre><p>V3 is not supposed to know about the existence of the VectorSpace (former R3) interface. There could be a different three-space interface that also has dot().</p> <p>The given code is only a concept to show my problem. The &#34;comma, ok&#34; idiom would only further bloat the code.</p></pre>ChristophBerger: <pre><p>I see what you mean. But if you change</p> <pre><code>var e V2 = c.sub(d) </code></pre> <p>to</p> <p>e := (c.sub(d)).(V2)</p> <p>then you can change all occurrences of <code>interface{}</code> to <code>VectorSpace</code>, and the code still works.</p> <p><a href="https://play.golang.org/p/KfLw3UucD4" rel="nofollow">Playground link</a></p> <p>The problem of having another interface with the same functions (<code>dot()</code> etc.) could be resolved by using different names (<code>vdot()</code>, <code>sdot()</code>, <code>mdot()</code>). Sure, this is not very elegant but it helps working around the fact that Go has no method overloading.</p></pre>jerf: <pre><blockquote> <p>V3 is not supposed to know about the existence of the VectorSpace (former R3) interface.</p> </blockquote> <p>This is kind of what I was getting at when I mentioned that this is Go biting you very hard. I can tell you right now that you can basically give up on having a nicely-typed vector library; the things you are trying to do are not implementable/expressible in Go as it stands now. (You can have a <em>not</em>-nicely typed vector library with vectors that <em>do</em> know about R<sup>3</sup> and all other such things you may want to implement, but not one that is &#34;proper&#34;.) You can hack a bit around this or you can hack a bit around that, but you spend your entire &#34;type system design budget&#34; long before your vector library is &#34;done&#34;.</p> <p>I don&#39;t know exactly what you&#39;re shooting for here, but you might consider Haskell instead; it has the type system to be able to do all these things.</p> <p>Or, alternatively, if you&#39;re just trying Go out, I suggest taking on a network project instead. For instance, I recently bashed out a little media player server that reads a directory, sorts things by movies or music, auto-generates m3u files for directories with MP3s in them, and dispatches back to the default file server in the standard library for serving the media files themselves so I don&#39;t have to implement the range stuff. It&#39;s not on Github right now (maybe someday), but that&#39;s a nice bite-size project (I put like probably a total of 6-8 hours into it, you&#39;ll take more if you&#39;re still learning because I&#39;ve been doing Go for like 4 years now, but it&#39;s still a nice project). But, you know, whatever you like.</p></pre>BromoL: <pre><blockquote> <p>I don&#39;t know exactly what you&#39;re shooting for here</p> </blockquote> <p>I am trying to educate myself. I spend most of the time with C. I also know C++, Java and some Python. So i feel myself quite limited in the choices that are available to me and want to extend my toolset. I think it is always worthwhile to push a new programming language to its limits. But especially with a new language it is difficult to decide whether the limits come from my limited understanding or are inherent to the language itself.</p> <p>Thanks for the suggestion of Haskell.</p></pre>jerf: <pre><p>Ah, thank you. That is my new language policy as well. Yes, can confirm, these limits are coming from Go, not you. Have fun!</p></pre>ChristophBerger: <pre><blockquote> <p>And that will panic</p> </blockquote> <p>unless you use the comma, ok idiom.</p> <pre><code>b, ok := bIn.(V3) if ok { return a.x*b.x + a.y*b.y + a.z*b.z } </code></pre></pre>

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

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