Как присвоить func для типа по отражению? - PullRequest
0 голосов
/ 02 января 2019

Я пишу RPC-сервис на Go. Я не знаю, как преобразовать метод struct в Handler func.

Что я пробовал:

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

Но это не удалось. Как мне это сделать?

1 Ответ

0 голосов
/ 02 января 2019

Метод TestService.Foo имеет тип func(a int) error, который не совпадает с типом Handle (Handle имеет тот же базовый тип, но это новый, отдельный тип).

Вы должны проверить для этого точного типа:

case func(a int) error:
    fmt.Println(" okokok ")

С этим изменением результат будет:

=== RUN   TestHandle
 okokok 
--- PASS: TestHandle (0.00s)
PASS

Попробуйте на Go Playground .

Обратите внимание, что вы можете сделать то же самое с утверждением типа , например:

if _, ok := reflect.Indirect(val).Method(0).Interface().(func(a int) error); ok {
    fmt.Println(" okokok ")
}

Попробуйте это на Go Playground .

Также обратите внимание, что если вы хотите использовать определение типа Handle, вы можете проверить, является ли значение функции присваиваемым переменной типа Handle.Используя рефлексию, эта проверка по сути означает, что тип метода можно назначить типу Handle.

. Вот как это будет выглядеть:

th := reflect.TypeOf(Handle(nil))
if reflect.Indirect(val).Method(0).Type().AssignableTo(th) {
    fmt.Println(" okokok ")
}

Попробуйте Go Playground .

Получение значения функции

Решения, приведенные выше, только проверяют, относится ли данный метод к указанному типу функции.Если вам также нужно значение функции (чтобы ее можно было вызвать), вот как вы можете это сделать:

При использовании переключателя типа ( 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())
}

При использовании утверждения типа ( Go Playground ):

if hf, ok := reflect.Indirect(val).Method(0).Interface().(func(a int) error); ok {
    fmt.Println(" okokok ", hf(0))
}

Использование 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))
}
...