如何实现两个方法名相同、参数不同的接口

问题描述 投票:0回答:4

我想实现两个不同的接口(来自两个不同的包)。但它们之间存在冲突,就像这样:

type InterfaceA interface {
  Init()
}

type InterfaceB interface {
  Init(name string)
}

type Implementer struct {} // Wants to implement A and B

func (i Implementer) Init() {}

func (i Implementer) Init(name string) {} // Compiler complains

它说“方法重新声明”。一个结构如何实现两个接口?

go interface
4个回答
6
投票

正如已经回答的,这是不可能的,因为 Golang 不(并且可能不会)支持方法重载。

查看Golang常见问题解答

其他语言的经验告诉我们,拥有相同名称但不同签名的多种方法有时是有用的,但在实践中也可能会造成混乱和脆弱。仅按名称匹配并要求类型一致是 Go 类型系统中的一个重大简化决策。


3
投票

这是不可能的。

在 go 中你必须有一个单一的方法签名。

您应该重命名一种方法。


0
投票

一个结构如何实现两个接口?

嗯......这取决于你是否可以在你的“一个结构”周围放置一个包装器。

如果您发现包装结构是不可接受的……那么其他贡献者所写的就是正确的!确实,Go 不允许这种方法重载。

但是,如果您包装

Implementer
类型...那么您可以毫无问题地实现这两个接口。

这是解决方法...

type InterfaceA interface {
    Init()
}

type InterfaceB interface {
    Init(name string)
}

type Implementer struct{} // Your one struct

type ImpA Implementer     // Wrapped version to implement InterfaceA
type ImpB Implementer     // Wrapped version to implement InterfaceB

func (i ImpA) Init() {}

func (i ImpB) Init(name string) {}

如果你去游乐场,你会发现它运行得很好!

去playground演示上面的代码!


-1
投票

方法签名必须匹配。如果您想要依赖注入,我会推荐功能选项模式。函数选项是返回在构造函数中循环调用的其他函数的函数。这是一个如何在 go 中使用功能选项和接口基础知识的示例。

package main

import (
    "fmt"
    "strconv"
)
type SomeData struct {
    data string
}
// SomeData and SomeOtherData both implement SomeInterface and SomeOtherInterface
// SomeInterface and SomeOtherInterface both implement each other.
type SomeInterface interface {
    String() string
    Set(data string)

}

func (s *SomeData)String() string {
    return s.data
}

func (s *SomeData)Set(data string)  {
    s.data = data
}

// SetDataOption is a functional option that can be used to inject a constructor dep
func SetDataOption(data string) func(*SomeData) {
   return func(s *SomeData) {
       s.Set(data)
   }
}
// NewSomeData is the constructor; it takes in 0 to many functional options and calls each one in a loop.
func NewSomeData(options ...func(s *SomeData)) SomeInterface {
   s := new(SomeData)

   for _, o := range options {
       o(s)
   }
   return s
}

//********************
type SomeOtherData struct {
    data string
    i    int
}

type SomeOtherInterface interface {
    String() string
    Set(data string)

}


func (s *SomeOtherData)String() string {
    return s.data + "  " + strconv.Itoa(s.i)
}

func (s *SomeOtherData)Set(data string)  {
    s.data = data
}


func SetOtherDataOption(data string) func(*SomeOtherData) {
   return func(s *SomeOtherData) {
      s.Set(data)
   }
}

func SetOtherIntOption(i int) func(*SomeOtherData) {
    return func(s *SomeOtherData) {
        s.i = i
    }
 }


// NewSomeOther data works just like NewSomeData only in this case, there are more options to choose from
// you can use none or any of them.
func NewSomeOtherData(options ...func(s *SomeOtherData)) SomeOtherInterface {
   s := new(SomeOtherData)

   for _, o := range options {
       o(s)
   }
   return s
}

//*********************************
// HandleData accepts an interface
// Regardless of which underlying struct is in the interface, this function will handle 
// either by calling the methods on the underlying struct.
func HandleData(si SomeInterface) {
    fmt.Println(si)  // fmt.Println calls the String() method of your struct if it has one using the Stringer interface
}

func main() {
    someData := NewSomeData(SetDataOption("Optional constructor dep"))
    someOtherData := NewSomeOtherData(SetOtherDataOption("Other optional constructor dep"), SetOtherIntOption(42))
    HandleData(someData) // calls SomeData.String()
    HandleData(someOtherData) // calls SomeOtherData.String()
    someOtherData = someData // assign the first interface to the second, this works because they both implement each other.
    HandleData(someOtherData) // calls SomeData.String()  because there is a SomeData in the someOtherData variable.
    
}
© www.soinside.com 2019 - 2024. All rights reserved.