Convert function to another type (function casting) in Go

huangapple go评论72阅读模式
英文:

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是一个匿名函数吗?

其次,在我去掉星号后,它可以正常工作,但为什么?opaaa类型的实例,接收者是opop代表函数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()
}

要么将指针传递给bfeelsGood方法:

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).

huangapple
  • 本文由 发表于 2014年4月7日 14:05:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/22904691.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定