英文:
Convert function to another type (function casting) in Go
问题
我最近学到了在net/http
包中有一种使用模式经常让我感到困惑。它是函数类型转换。具体如下:
(函数 a) -> 转换为 -> (类型 t)
(类型 t) -> 实现 -> (接口 i)
所以,如果有一个函数以接口i
作为参数,它将调用函数a,这是net/http
实现的方式。
但是当我编写自己的代码时,我对这种模式有很多误解。我的代码如下:
package main
import (
"fmt"
)
type eat interface {
eat()
}
type aaa func()
func (op *aaa) eat() {//指针接收者不正确
fmt.Println("dog eat feels good")
}
///////////////////////////////////////////////
func dog() {
fmt.Println("I'm a dog")
}
///////////////////////////////////////////////
func feelsGood(a eat) {
a.eat()
}
func main() {
b := aaa(dog)
feelsGood(b)
}
//错误:aaa没有实现eat(eat方法具有指针接收者)
类型aaa具有方法eat,与接口eat的规则相符,但为什么会出现错误?接收者是否重要?
另一个问题是只有一个函数和类型,不包括接口,代码如下:
package main
import (
"fmt"
)
type aaa func()
func (op *aaa) eat() {
op()
}
///////////////////////////////////////////////
func dog() {
fmt.Println("I'm a dog")
}
///////////////////////////////////////////////
func main() {
obj := aaa(dog)
obj.eat()
}
//错误:无法调用非函数op(类型*aaa)
首先,不考虑错误,op
是一个匿名函数吗?
其次,在我去掉星号后,它可以正常工作,但为什么?op
是aaa
类型的实例,接收者是op
,op
代表函数dog()
吗?http包也以相同的方式使用f(w,r)
,但有点难以理解。op
是一种类型,还是一个实例,还是一个匿名函数?
似乎我的函数转换理解不正确,但我也查阅了许多Google上的帖子,没有一个可以教我如何正确思考和使用它。谢谢!
英文:
I've recently learnt that in the net/http
package, there's a pattern of usage that keeps confusing me most. It is function type conversion. It is like this:
(function a) ->convert to-> (type t)
(type t) ->implentments-> (interface i)
So, if there's a function that takes interface i
as its parameter, it will invoke the function a, this is the way net/http
implements it.
But when I write my own code, I've had many misunderstandings on this pattern. My code goes like this:
package main
import (
"fmt"
)
type eat interface {
eat()
}
type aaa func()
func (op *aaa) eat() {//pointer receiver not right
fmt.Println("dog eat feels good")
}
///////////////////////////////////////////////
func dog() {
fmt.Println("I'm a dog")
}
///////////////////////////////////////////////
func feelsGood(a eat) {
a.eat()
}
func main() {
b := aaa(dog)
feelsGood(b)
}
//error:aaa does not implement eat (eat method has pointer receiver)
Type aaa has method eat, the same function name and parameter signature, which conforms to the rule of interface eat, but why does it give that error? Does the receiver matter?
Another question is with only a function and type, excluding an interface, the code goes like this:
package main
import (
"fmt"
)
type aaa func()
func (op *aaa) eat() {
op()
}
///////////////////////////////////////////////
func dog() {
fmt.Println("I'm a dog")
}
///////////////////////////////////////////////
func main() {
obj:=aaa(dog)
obj.eat()
}
//error:cannot call non-function op (type *aaa)
First, is op
an anonymous function, regardless of the error?
Second, it works well after I remove the asterisk, but why? op
is instance of type aaa
, receiver is op
, does op
stand for function dog()? The http package uses f(w,r)
the same way, but it is a little bit of hard to understand. Is op
a type, or an instance, or an anonymous function?
It seems like my comprehension of function converting is not right, but I've also checked many posts on Google, and none of them can teach me how to think of it and use it correctly.Thank you!
答案1
得分: 9
问题1:
在Go语言中,对于类型T(例如你的例子中的aaa),T
和*T
有不同的方法集。
因此,类型T的值只能访问方法:
func (t T) Foo() { ... }
而类型*T的值可以同时访问以下两个方法:
func (t T) Foo() { ... }
func (t *T) Bar() { ... }
在你的情况下,你有两个选择。要么为aaa声明eat
方法而不是*aaa
:
func (op aaa) eat() {
op()
}
要么将指针传递给b
的feelsGood
方法:
feelsGood(&b)
问题2:
是的,这个问题与第一个问题有关。但在这种情况下,你可以访问该方法,因为obj.eat()
等同于(&obj).eat()
。
你在这里的问题是无法在函数指针(op *aaa)上调用函数。你有两个选择,要么为aaa创建方法而不是*aaa
:
func (op aaa) eat() {
op()
}
要么在值上调用op
函数而不是指针:
func (op *aaa) eat() {
(*op)()
}
英文:
Question 1:
In Go, for a type T (like aaa in your case), T
and *T
have different method sets.
So, a value of type T can only access method:
func(t T)Foo() { ... }
While a value of type *T can access both methods:
func(t T)Foo() { ... }
func(t *T)Bar() { ... }
In your case, you have two options. Either you declare the eat
method for aaa
instead od *aaa
:
func (op aaa) eat() {
op()
}
Or you pass the pointer to b
to feelsGood
:
feelsGood(&b)
Question 2:
Yes, this question is related to the first. But in this case you can access the method because obj.eat()
will be short for (&obj).eat()
.
Your problem here is that you cannot call a function on the function pointer (op *aaa). Your options are to either create the method for aaa
instead of *aaa
:
func (op aaa) eat() {
op()
}
Or to call the op
function on the value and not the pointer:
func (op *aaa) eat() {
(*op)()
}
答案2
得分: 2
关于你问题的第一部分,请参考http://golang.org/doc/faq#different_method_sets,该链接比我能解释得更清楚。你还可以在stackoverflow和golang-nuts邮件列表中搜索这个问题,因为这个问题经常出现。
第二部分的情况与此类似:aaa
没有eat
方法(只有*aaa
有)。
英文:
For the first part of your question: See http://golang.org/doc/faq#different_method_sets which exmplains everything better than I could. You may even search stackoverflow and the golang-nuts mailing list for this question as this comes up very often.
The second is just the same IMHO: aaa
doesn't have an eat
-method (only *aaa
has).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论