首页 > 解决方案 > Go 接口在方法之间强制执行相同的参数类型(但可以是任何类型)

问题描述

我敢肯定,标题令人困惑,但很难描述我的意思。

我想创建一个有两种方法的 Go 接口;第一个返回一个值,第二个接受一个值。我想确保方法 1 返回与方法 2 接受的类型相同的类型,而不指定类型是什么(除了它是一个结构)。例如:

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

whereMyType可以是任何类型(结构),只要它在方法 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{})
}

所以基本上,我指定了一个接口MyInterfaceMyImplementation

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 {}

标签: gointerface

解决方案


将以下函数添加到包中,以确保在编译时输入和输出类型匹配:

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

只要不调用该函数,该函数就不会包含在可执行文件中。

没有编译时检查可以确保它MyType是问题中指定的结构类型。

reflect 包可用于完全检查类型类型。

// 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")
   }
}

推荐阅读