英文:
How to implement two interfaces with same method name and different arguments
问题
我有两个不同的接口(来自两个不同的包),我想要实现它们。但是它们发生了冲突,就像这样:
type InterfaceA interface {
Init()
}
type InterfaceB interface {
Init(name string)
}
type Implementer struct {} // 想要实现 A 和 B
func (i Implementer) Init() {}
func (i Implementer) Init(name string) {} // 编译器报错
它说"方法重复声明"。如何让一个结构体实现这两个接口呢?
英文:
I have two different interfaces (from two different packages) that I want to implement. But they conflict, like this:
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
It says "Method redeclared". How can one struct implement both interfaces?
答案1
得分: 6
如前所述,这是不可能的,因为Golang不支持(也可能永远不会支持)方法重载。
请参考Golang FAQ:
从其他语言的经验来看,拥有多个具有相同名称但不同签名的方法有时可能很有用,但在实践中可能会令人困惑和脆弱。在Go的类型系统中,只通过名称匹配并要求类型一致是一个重要的简化决策。
英文:
As already answered, this is not possible since Golang does not (and probably will not) support method overloading.
Look at Golang FAQ:
> Experience with other languages told us that having a variety of methods with the same name but different signatures was occasionally useful but that it could also be confusing and fragile in practice. Matching only by name and requiring consistency in the types was a major simplifying decision in Go's type system.
答案2
得分: 3
这是要翻译的内容:
这是不可能的。
在Go语言中,你必须有一个单一的方法签名。
你应该重命名一个方法。
英文:
It is not possible.
In go you must have a single method signature.
You should rename one method.
答案3
得分: -1
方法签名必须匹配。如果你想要依赖注入,我建议使用函数选项模式(functional option pattern)。函数选项是返回其他函数的函数,在构造函数中循环调用这些函数。以下是如何使用函数选项和Go语言接口的基础知识的示例。
package main
import (
"fmt"
"strconv"
)
type SomeData struct {
data string
}
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
}
func SetDataOption(data string) func(*SomeData) {
return func(s *SomeData) {
s.Set(data)
}
}
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
}
}
func NewSomeOtherData(options ...func(s *SomeOtherData)) SomeOtherInterface {
s := new(SomeOtherData)
for _, o := range options {
o(s)
}
return s
}
func HandleData(si SomeInterface) {
fmt.Println(si)
}
func main() {
someData := NewSomeData(SetDataOption("Optional constructor dep"))
someOtherData := NewSomeOtherData(SetOtherDataOption("Other optional constructor dep"), SetOtherIntOption(42))
HandleData(someData)
HandleData(someOtherData)
someOtherData = someData
HandleData(someOtherData)
}
以上是一个使用函数选项和接口的示例代码。
英文:
The method signatures must match. If you want dependency injection I would recommend the functional option pattern. Functional options are functions that return other functions that are called in a loop in the constructor. Here is an example of how to use functional options and the basics of interfaces in 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.
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论