英文:
In "A Go Tour", how do I modify the interface to require a method on a pointer?
问题
在《A Go Tour》中的接口部分,我们有以下接口:
type Abser interface {
Abs() float64
}
解释说,这个类型Vertex不满足上述的Abser接口:
type Vertex struct {
X, Y float64
}
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
我应该如何修改Abser接口,使得Vertex满足它?
(如果在完整示例中不再满足MyFloat也没关系。)
在发布这个问题之前,我花了几个小时搜索和思考,但在发布后,我发现了另一个类似的问题,它涵盖了类似的内容,可能对其他初学者有帮助:
《Go编程语言中的“方法需要指针接收者”》
英文:
In "A Go Tour" on Interfaces we have this interface:
type Abser interface {
Abs() float64
}
It is explained that this type, Vertex, does not satisfy the above Abser:
type Vertex struct {
X, Y float64
}
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
How do I modify the Abser interface so that Vertex satisfies it?
(It's okay if it no longer satisfies MyFloat in the full example.)
Before I posted this question I spent some hours searching and head scratching but after posting I found another SO question which covers similar material and may be of help to other neophytes:
"method requires pointer receiver” in Go Programming Language
答案1
得分: 2
你对实现关系有些困惑。在这种情况下,*Vertex
实现了 Abser
接口,而不是 Vertex
,如果你想让 Vertex
也实现该接口,你需要在 Abs
的实现中改变接收类型,使其不是指针类型:
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
} // 这里是 Vertex 实现 Abser
所以你提出的问题有点误导。接口不需要任何更改,也不应该有任何更改。只是提醒一下,你可以通过使用我上面提到的方法以及你已经有的方法,让 *Vertex
和 Vertex
都实现该接口。
这是 Go 中经常让人困惑的一点。当你声明 func (t SomeType)
时,你指定了接收类型,如果这是一个指针,比如 (t *SomeType)
,那么实现接口的是 *SomeType
而不是 SomeType
。这与其他语言有些不同,其他语言中方法是由类实现的,无论你使用引用还是值都没有关系。在 Go 中,类并不实现方法,你指定的是接收类型,即方法可以在其上调用的类型。第一个参数实际上被推送到堆栈上,并像传递给方法的参数一样使用,这种区别只在编译时有意义(我认为实现接口是唯一需要此功能的原因)。所以,总结一下,如果你想让 Vertex
实现 Abser
接口,该接口包含一个方法 Abs() float64
,那么你需要将函数定义为 func (v Vertex) Abs() float64 { ... }
。
出于代码清晰可读的考虑,我建议不要同时为指针和值定义接口...你可以使用取地址操作符或解引用操作符来解决这个问题。
英文:
You're slightly confused about what is implementing what. In this case, *Vertex
is implementing Abser
and not Vertex
to make it so Vertex
does as well, you have to change the receiving type on your implementation of Abs
so that it's not a pointer;
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
} // Vertex implementing Abser here
So the way you're phrasing the question is a bit misleading. The interface requires no change and should receive none. Just fyi, you can have both *Vertex
and Vertex
implement the interface by using the method I put above as well as the one you already have.
This is a point that often trips people up in Go. When you declare func (t SomeType)
you're specifying the receiving type, if this is a pointer like (t *SomeType)
then the thing implementing the interface is not SomeType
but rather *SomeType
. This differs a little from other languages where the method is implemented by the class and it doesn't matter if you're working with a reference or a value. In Go, the class doesn't implement the method, you specify the 'receiving type' - the thing that the method can be called on - that first argument actually gets pushed on the stack and used the same as an argument passed into a method, the distinction is only relevant for compilation (interface fulfillment really is the only reason to have the feature afaik). So, to summarize, if you want Vertex
to implement the Abser
interface which features a single method Abs() float64
then you need to define the function as func (v Vertex) Abs() float64 { ... }
.
Just for the sake of having clear readable code I recommend not having the interface defined for both pointers and values... You can work around that using the address of or dereference operator.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论