Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert function to another type (function casting) in Go

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!

like image 745
Dew Avatar asked Dec 20 '22 16:12

Dew


1 Answers

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)()
}
like image 156
ANisus Avatar answered Dec 24 '22 03:12

ANisus