【问题标题】:Convert function to another type (function casting) in Go在 Go 中将函数转换为另一种类型(函数转换)
【发布时间】:2014-05-19 05:45:32
【问题描述】:

我最近了解到,在 net/http 包中,有一种使用模式最让我感到困惑。是函数类型转换。是这样的:

(function a) ->convert to-> (type t)
(type t) ->implentments-> (interface i)

所以,如果有一个函数以接口i为参数,它会调用函数a,这就是net/http的实现方式。

但是当我编写自己的代码时,我对这种模式有很多误解。我的代码是这样的:

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)

类型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()
}
//error:cannot call non-function op (type *aaa)

首先,op 是匿名函数,不管错误如何?

其次,我去掉星号后效果很好,但为什么呢? opaaa 类型的实例,接收者是 opop 是否代表函数 dog()? http包同样使用f(w,r),但是理解起来有点难。 op 是类型、实例还是匿名函数?

看来我对函数转换的理解是不对的,不过我也查了很多谷歌的帖子,都没有教我怎么去思考和正确使用。谢谢!

【问题讨论】:

    标签: function types go type-conversion


    【解决方案1】:

    问题 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)()
    }
    

    【讨论】:

    • 但是,我只声明了T类型,*T类型根本不存在,那么,不存在的*T类型怎么可能实现接口呢?还有,即使*T类型存在,T和*T有什么区别,我唯一能想到的是*T是指向T的指针,指针的方法VS普通的方法,这是什么意思?思考!
    • 我读过其他关于何时应该使用 T 函数以及何时应该使用 *T 函数的帖子,他们都告诉我,如果你想修改接收器本身,那么你应该使用 *T,否则你应该使用T,但是在这种情况下,我将如何使用上述考虑来解释应该使用T还是*T方法?
    • @user3505400: *T 在声明 T 时被隐式声明为指向 T 的指针,因此它确实存在。是的,区别主要在于您是否可以修改接收器。那么为什么 Go 不直接将指针指向接口中的值呢?这是因为(afaIk)当您将值传递给函数a := struct{42}; Foo(a) 时,您应该可以放心a 不会被更改。
    【解决方案2】:

    对于您问题的第一部分:请参阅http://golang.org/doc/faq#different_method_sets,它比我能更好地解释一切。你甚至可以在 stackoverflow 和 golang-nuts 邮件列表中搜索这个问题,因为这个问题经常出现。

    第二个也是一样的恕我直言:aaa 没有 eat 方法(只有 *aaa 有)。

    【讨论】:

      猜你喜欢
      • 2010-10-08
      • 1970-01-01
      • 1970-01-01
      • 2014-05-25
      • 2011-05-17
      • 2023-02-07
      相关资源
      最近更新 更多