<p>The following does not work, how can this be fixed?</p>
<pre><code>package main
import "fmt"
import "math"
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 "dot(V3) float64" and not "dot(R3) float64"
}
</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'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're playing around with, well, it's all up to you of course but I'd take this as a sign of a real characteristic of Go.</p></pre>BromoL: <pre><p>Ok, thanks. That's what I already suspected. But</p>
<pre><code>func (a V3) dot(bIn R3) float64
</code></pre>
<p>isn'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 "fmt"
import "math"
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 "comma, ok" 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 "comma, ok" 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 "proper".) You can hack a bit around this or you can hack a bit around that, but you spend your entire "type system design budget" long before your vector library is "done".</p>
<p>I don't know exactly what you'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'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't have to implement the range stuff. It's not on Github right now (maybe someday), but that's a nice bite-size project (I put like probably a total of 6-8 hours into it, you'll take more if you're still learning because I've been doing Go for like 4 years now, but it's still a nice project). But, you know, whatever you like.</p></pre>BromoL: <pre><blockquote>
<p>I don't know exactly what you'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
0 回复
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传