2

我正在为我正在编写的玩具包编写规范,虽然大部分规范都保证包中的各种结构满足主要的公共接口,但我也有兴趣指定接口必须要求的方法;我知道这有点迂腐,但我认为这将是一个巧妙的实验,并且会施加压力以保持公共界面的稳定。

这是我的第一次尝试:

type Roller interface {
        Min()  int
}

type minS struct {}
func (m minS) Min() int {return 0}
func (m minS) Max() int {return 0}

func RollerSpec(c gospec.Context) {

        var r Roller = minS{}

        c.Specify("has a minimum value.", func() {
                _, ok := r.(interface{Min() int})
                c.Expect(ok, Equals, true)
        })

        c.Specify("has a maximum value.", func() {
                _, ok := r.(interface{Max() int})
                c.Expect(ok, Equals, true)
        })

        c.Specify("has an expected value.", func() {
                _, ok := r.(interface{Exp() int})
                c.Expect(ok, Equals, true)
        })

        c.Specify("can be rolled.", func() {
                _, ok := r.(interface{Roll() int})
                c.Expect(ok, Equals, true)
        })
}

如您所见,我的Roller界面只需要Min()但同时minS实现了Min()Max()。我通过了前两个规范,即使Runner不满足interface{Max() int}因为我用来测试它的虚拟类型。同样,在没有基类型的情况下声明 r 会导致它无法满足所有规范。

很明显,为什么 Go 会在接口之间对实际存储的类型进行类型断言,但这不是我在这里寻找的。我还检查了反射包,但它似乎也只检查结构。有没有办法以编程方式检查接口是否需要给定的方法,而无需自己拉入解析包并爬取解析树以获取方法名称?

4

3 回答 3

2

简单地说,你不能。没有办法只存储一个接口,因为它不是一个具体类型,并且反射只适用于具体类型。请参阅反射包及其文档。

无论如何,您想做的事情似乎没有必要。界面是您的规格。看起来你想要做的是编写一个规范来描述你的规范,一旦你这样做了,最大的问题就是你在哪里停下来。一路下来都是乌龟:-)

于 2012-08-30T18:27:01.267 回答
1

具有单个接口的简单类型断言应该可以做到。

type minRoller interface {
    Min() int
}

type maxRoller interface {
    Max() int
}

在你的测试中:

if _, ok := r.(minRoller); ok {
    print("has a min value")
}
if _, ok := r.(maxRoller); ok {
    print("has a max value") 
}

您的 Roller 界面可以嵌入较小的界面:

type MinRoller interface {
    minRoller
}

type MinMaxRoller interface {
    minRoller
    maxRoller
}
于 2012-08-30T08:40:01.743 回答
0

当然有一种方法 -reflect.Type接口包含reflect.Method与接口方法相对应的方法(但不要尝试调用这些方法!请参阅我的问题Go reflection with interface embedded in struct - how to detect “real” functions?

使用它,循环访问接口的方法并检查这些方法是否也存在于另一个接口中(几乎)是微不足道的:

func InterfaceExtendsInterface(parent reflect.Type, child reflect.Type) bool {
    if parent.Kind() != reflect.Interface || child.Kind() != reflect.Interface {
        return false
    }
    for i := 0; i < parent.NumMethod(); i++ {
        m := parent.Method(i)
        if n, has := child.MethodByName(m.Name); !has {
            return false
        } else if !reflect.DeepEqual(m,n) {
            return false
        }
    }
    return true
}

由于接口“扩展”(在接口中嵌入接口)的工作方式,我真的看不出两者之间的区别

type Foo interface {...}
type Bar interface { Foo; ... }
type Baz struct { ... } // reflect.TypeOf(Baz{}).CovertibleTo(reflect.TypeOf([]Bar{}).Elem())

和稍弱的

type Foo interface {...}
type Bar interface { ... }
type Baz struct { ... } // reflect.TypeOf(Baz{}).CovertibleTo(reflect.TypeOf([]Bar{}).Elem()) && 
                        // reflect.TypeOf(Baz{}).CovertibleTo(reflect.TypeOf([]Foo{}).Elem())

以至于我什至无法想到任何情况下,这两者会暗示对 ... 实例的非反射调用具有不同的语义(当然,如果不嵌入它,则必须直接Baz转换为)FooBar

于 2015-05-19T18:07:53.393 回答