Reputation: 23
I am writing an RPC service in Go. I don't know how to convert a struct method to a Handler
func.
What I tried:
type TestService struct{}
func (TestService) Foo(a int) error {
return nil
}
type Handle func(a int) error
func TestHandle(t *testing.T) {
ts := new(TestService)
val := reflect.ValueOf(ts)
// typ := reflect.TypeOf(ts)
// fmt.Println(val.Method(0).Interface())
// fmt.Println(val.Method(0).Type().ConvertibleTo(reflect.TypeOf(new(Handle))))
switch reflect.Indirect(val).Method(0).Interface().(type) {
case Handle:
fmt.Println(" okokok " )
default:
fmt.Println(reflect.Indirect(val).Method(0).Type())
}
}
But it fails. How should I do it?
Upvotes: 2
Views: 1400
Reputation: 417592
The method TestService.Foo
is of type func(a int) error
, which is not the same as type Handle
(Handle
has the same underlying type, but it is a new, distinct type).
You have to check for this exact type:
case func(a int) error:
fmt.Println(" okokok ")
With this change, output will be:
=== RUN TestHandle
okokok
--- PASS: TestHandle (0.00s)
PASS
Try it on the Go Playground.
Note that you can do the same with a type assertion, e.g.:
if _, ok := reflect.Indirect(val).Method(0).Interface().(func(a int) error); ok {
fmt.Println(" okokok ")
}
Try this one on the Go Playground.
Also note that if you do want to use the Handle
type definition, you could check if the function value is assignable to a variable of Handle
type. Using reflection, this check essentially means if the type of the method is assignable to the type of Handle
.
This is how it would look like:
th := reflect.TypeOf(Handle(nil))
if reflect.Indirect(val).Method(0).Type().AssignableTo(th) {
fmt.Println(" okokok ")
}
Try this one on the Go Playground.
Solutions above only check if the given method is of the given function type. If you also need the function value (so you can call it), this is how you can do it:
When using type switch (Go Playground):
switch hf := reflect.Indirect(val).Method(0).Interface().(type) {
case func(a int) error:
fmt.Println(" okokok ", hf(0))
default:
fmt.Println(reflect.Indirect(val).Method(0).Type())
}
When using type assertion (Go Playground):
if hf, ok := reflect.Indirect(val).Method(0).Interface().(func(a int) error); ok {
fmt.Println(" okokok ", hf(0))
}
Using Value.Convert()
(Go Playground):
m := reflect.Indirect(val).Method(0)
th := reflect.TypeOf(Handle(nil))
if m.Type().AssignableTo(th) {
var hf Handle = m.Convert(th).Interface().(Handle)
fmt.Println(" okokok ", hf(0))
}
Upvotes: 3