代码之家  ›  专栏  ›  技术社区  ›  muffel

可以在go中定义匿名接口实现吗?

  •  2
  • muffel  · 技术社区  · 5 年前

    考虑一些给定的接口和一个假想库的函数

    // Binary and Ternary operation on ints
    type NumOp interface {
        Binary(int, int) int
        Ternary(int, int, int) int
    }
    
    func RandomNumOp(op NumOp) {
        var (
            a = rand.Intn(100) - 50
            b = rand.Intn(100) - 50
            c = rand.Intn(100) - 50
        )
        fmt.Printf("%d <op> %d = %d\n", a, b, op.Binary(a,b))
        fmt.Printf("%d <op> %d <op> %d = %d\n", a, b, c, op.Ternary(a,b,c))
    }
    

    实现该接口的可能类型可以是

    // MyAdd defines additions on 2 or 3 int variables
    type MyAdd struct {}
    func (MyAdd) Binary(a, b int) int {return a + b }
    func (MyAdd) Ternary(a, b, c int) int {return a + b + c }
    

    我正在处理许多不同的接口,这些接口定义了一些在某些情况下需要使用主要工作为 NOP -与操作类似,不依赖任何结构 成员 并且仅用于项目中的单个位置(不需要重用性)。

    Go中是否有一种更简单(不太冗长)的方法来使用匿名函数定义接口的匿名实现(最好是匿名实现),就像(伪代码,我知道它不是这样工作的):

    RandomNumOp({
       Binary: func(a,b int) int { return a+b},
       Ternary: func(a,b,c int) int {return a+b+c},
    })
    
    1 回复  |  直到 5 年前
        1
  •  5
  •   icza    5 年前

    如果必须实施

    如果实现接口的值必须有效(例如,它的方法必须可以调用而不必惊慌),那么就不能这样做。

    方法声明必须位于顶层(文件级)。要实现一个方法多于0个的接口,需要在某个地方有方法声明。

    当然,您可以使用一个结构并嵌入一个现有的实现,但同样,它要求已经有一个现有的实现,其方法必须已经在文件级“某处”定义。

    如果您需要一个“虚拟”但可行的实现,它们使用/通过 任何 实现,例如 MyAdd 类型。如果您想强调实现并不重要,那么创建一个虚拟实现,其名称指示:

    type DummyOp struct{}
    
    func (DummyOp) Binary(_, _ int) int     { return 0 }
    func (DummyOp) Ternary(_, _, _ int) int { return 0 }
    

    如果您需要为 一些 在这些方法中,您可以动态地创建一个拥有这些方法的函数的委托结构类型,并且实际的方法检查是否设置了相应的函数,在这种情况下,调用它,否则什么都不做。

    这就是它看起来的样子:

    type CustomOp struct {
        binary  func(int, int) int
        ternary func(int, int, int) int
    }
    
    func (cop CustomOp) Binary(a, b int) int {
        if cop.binary != nil {
            return cop.binary(a, b)
        }
        return 0
    }
    
    func (cop CustomOp) Ternary(a, b, c int) int {
        if cop.ternary != nil {
            return cop.ternary(a, b, c)
        }
        return 0
    }
    

    当使用它时,您可以自由地只提供函数的一个子集,其余的将是非操作:

    RandomNumOp(CustomOp{
        binary: func(a, b int) int { return a + b },
    })
    

    如果不要求实施工作

    如果您只需要一个实现接口的值,但不需要其方法是“可调用的”(如果调用,则不必惊慌),则只需使用匿名结构文本,嵌入接口类型:

    var op NumOp = struct{ NumOp }{}