douzi1350
douzi1350
2016-09-23 06:48

使用Golang中的结构体将方法转换为函数

I read some strange codes which convert a method to a function whose first argument is a pointer to this method's struct.

I write an example to demonstrate it:

package main

import "fmt"

type fooS struct{}

func (s *fooS) fooF(fooArg interface{}) {
    fmt.Println("fooF: ", fooArg)
}

type wowS struct {
    callback func(s *fooS, fooArg interface{})
}

func main() {
    wow := new(wowS)
    wow.callback = (*fooS).fooF // strange
    wow.callback(nil, 123)
}

Golang Playground Link

The example's syntax is strange but has no error.

Can any one tell me how these codes work or give me an official document about them?

Thanks:)

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

1条回答

  • dousou3027 dousou3027 5年前

    Method expressions:

    If M is in the method set of type T, T.M is a function that is callable as a regular function with the same arguments as M prefixed by an additional argument that is the receiver of the method.

    MethodExpr    = ReceiverType "." MethodName .
    ReceiverType  = TypeName | "(" "*" TypeName ")" | "(" ReceiverType ")" .
    

    Consider a struct type T with two methods, Mv, whose receiver is of type T, and Mp, whose receiver is of type *T.

    type T struct {
      a int
    }
    func (tv  T) Mv(a int) int         { return 0 }  // value receiver
    func (tp *T) Mp(f float32) float32 { return 1 }  // pointer receiver
    
    var t T
    

    The expression

    T.Mv
    

    yields a function equivalent to Mv but with an explicit receiver as its first argument; it has signature

    func(tv T, a int) int
    

    That function may be called normally with an explicit receiver, so these five invocations are equivalent:

    t.Mv(7)
    T.Mv(t, 7)
    (T).Mv(t, 7)
    f1 := T.Mv; f1(t, 7)
    f2 := (T).Mv; f2(t, 7)
    

    Similarly, the expression

    (*T).Mp 
    

    yields a function value representing Mp with signature

    func(tp *T, f float32) float32
    

    For a method with a value receiver, one can derive a function with an explicit pointer receiver, so

    (*T).Mv
    

    yields a function value representing Mv with signature

    func(tv *T, a int) int
    

    Such a function indirects through the receiver to create a value to pass as the receiver to the underlying method; the method does not overwrite the value whose address is passed in the function call.

    The final case, a value-receiver function for a pointer-receiver method, is illegal because pointer-receiver methods are not in the method set of the value type.

    Function values derived from methods are called with function call syntax; the receiver is provided as the first argument to the call. That is, given f := T.Mv, f is invoked as f(t, 7) not t.f(7). To construct a function that binds the receiver, use a function literal or method value.

    It is legal to derive a function value from a method of an interface type. The resulting function takes an explicit receiver of that interface type.


    And see:
    Go - difference between parameter and receiver
    Is there a performance penalty for passing "this" by value in Go methods?
    differences between pointer and value slice in for-range loop

    点赞 评论 复制链接分享

为你推荐