Go интерфейс для применения одного и того же типа аргумента между методами (но может быть любого типа) - PullRequest
0 голосов
/ 16 января 2020

Название озадачивает, я уверен, но трудно описать, что я имею в виду.

Я хочу создать интерфейс Go, который имеет два метода; первый возвращает значение, а второй принимает значение. Я хочу убедиться, что метод 1 возвращает тот же тип, что и метод 2, без указания типа (кроме структуры). Например:

type MyInterface interface {
    Method1() MyType
    Method2(MyType) error
}

Где MyType может быть любого типа (структуры), при условии, что оно одинаково как в методе 1, так и в методе 2.

Есть ли способ сделать это в Go?

РЕДАКТИРОВАТЬ:

Основываясь на ответе @ iLoveReflection, я попробовал следующее:

package main

type MyInterface interface {
    GetType() interface{}

    UseType(input interface{})
}

type MyImplementation struct{}

type MyType struct {
}

func (i MyImplementation) GetType() MyType {
    return MyType{}
}
func (i MyImplementation) UseType(input MyType) {
    return
}

func test(input MyInterface) {
    return
}

func assertArgAndResult() {
    var v MyImplementation
    v.UseType(v.GetType())
}

func main() {
    test(MyImplementation{})
}

Итак в основном я указываю интерфейс (MyInterface) и хочу убедиться, что данная реализация этого интерфейса (MyImplementation, которая будет создана пользователем моего пакета) соответствует требованию, указанному в исходном сообщении .

assertArgAndResult() работает должным образом и гарантирует, что MyImplementation соответствует требованиям. Тем не менее, я получаю ошибку компиляции в функции main():

cannot use MyImplementation literal (type MyImplementation) as type MyInterface in argument to test:
    MyImplementation does not implement MyInterface (wrong type for GetType method)
        have GetType() MyType
        want GetType() interface {}

1 Ответ

1 голос
/ 16 января 2020

Добавьте следующую функцию в пакет, чтобы гарантировать совпадение типов ввода и вывода во время компиляции:

func assertArgAndResult() {
    var v MyInterface
    v.Method2(v.Method1())
}

Эта функция не будет включена в исполняемый файл, пока функция не вызывается.

Нет проверки времени компиляции, которая бы гарантировала, что MyType является структурным типом, как указано в вопросе.

Пакет отражения можно использовать для полной проверки типов типов.

// checkItf returns true of the interface value pointed to by
// pi has Method1 with some return type T and Method2 with
// argument type T.
func checkItf(pi interface{}) bool {
    t := reflect.TypeOf(pi)
    if t.Kind() != reflect.Ptr {
        return false // or handle as error
    }
    t = t.Elem()
    if t.Kind() != reflect.Interface {
        return false // or handle as error
    }
    m1, ok := t.MethodByName("Method1")

    // Method1 should have no outputs and one input.
    if !ok || m1.Type.NumIn() != 0 || m1.Type.NumOut() != 1 {
        return false
    }

    // Method2 should have one input and one output.
    m2, ok := t.MethodByName("Method2")
    if !ok || m2.Type.NumIn() != 1 || m2.Type.NumOut() != 1 {
        return false
    }

    e := reflect.TypeOf((*error)(nil)).Elem()
    s := m1.Type.Out(0)

    // The type must be a struct and
    // the input type of Method2 must be the same as the output of Method1 and
    // Method2 must return error.
    return s.Kind() == reflect.Struct &&
        m2.Type.In(0) == s &&
        m2.Type.Out(0) == e
}

Назовите это так:

func init() {
   if !checkItf((*MyInterface)(nil)) {
      panic("mismatched argument and return time son MyInterface")
   }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...