说我有两个结构:
type First struct {
str string
}
type Second struct {
str string
}
我希望他们两个都实现接口A:
type A interface {
PrintStr() //print First.str or Second.str
}
对于第一个和第二个结构都有这样的实现似乎是多余的:
func (f First) PrintStr() {
fmt.Print(f.str)
}
func (s Second) PrintStr() {
fmt.Print(s.str)
}
有没有办法可以为实现接口A的所有结构实现一个实现?像这样的东西,但它似乎不起作用:
func (a A) PrintStr() {
fmt.Print(a.str)
}
谢谢!
答案 0 :(得分:14)
不,你不能,但是你可以创建一个基本类型,然后将它嵌入到你的2结构中,因此只需要基类型的实现:
type WithString struct {
str string
}
type First struct {
WithString
}
type Second struct {
WithString
}
type A interface {
PrintStr() //print First.str or Second.str
}
func (w WithString) PrintStr() {
fmt.Print(w.str)
}
用法:
a := First{
WithString: WithString{
str: "foo",
},
}
答案 1 :(得分:3)
如果打印逻辑依赖于界面而不依赖于结构本身,那么最好将打印移动到通过界面操作的自由函数。
在您的情况下,PrintStr
方法用于打印作为每个结构成员的字符串
在这种情况下,这意味着每个结构应该实现一个返回用于打印的必要字符串的接口,PrintStr
成为一个带有Printable
参数的函数。
type First struct {
str string
}
type Second struct {
str string
}
type Printable interface {
String() string
}
func (p First) String() string {
return p.str
}
func (p Second) String() string {
return p.str
}
func PrintStr(p Printable) {
fmt.Print(p.String())
}
您对A
界面的使用是非惯用的,因为界面不应依赖于其功能的实施。
相反,使用此解决方案,您仍然可以保留A接口,但会简化每个实现:
func (f First) PrintStr() {
PrintStr(f)
}
func (s Second) PrintStr() {
PrintStr(s)
}
它仍然是多余的,但逻辑在于从那里调用的函数,限制了在修改打印逻辑的情况下进行复制粘贴的需要。
这种模式在Go标准库中很常见,因为许多有用的函数是基于它们无法扩展的接口构建的,例如io.Reader。
它是一个只有一种方法的简单界面,但它可以从许多其他包中使用
如果你看一下ioutil.ReadAll函数,可以认为它可以作为io.Reader
接口的另一种方法实现,但是这使读者更简单,专注于他们的单一方法,同时允许任何实现者免费使用ReadAll。
答案 2 :(得分:2)
为什么不只是将该函数放在接口之外,而将类型A作为参数传递呢?
type A interface {}
type First struct {
str string
}
type Second struct {
str string
}
func PrintStr(a A) {
fmt.Print(a.str)
}
答案 3 :(得分:1)
也许不是解决问题的最佳方法,但你可以使用包装器来避免两次“实现”这个功能,如下所示:
type First struct {
str StringWrapper
}
type Second struct {
str StringWrapper
}
type StringWrapper struct {
str string
}
func (f StringWrapper) PrintStr() {
fmt.Print(f.str)
}
func main() {
var a First = First{str:StringWrapper{str: "aaa"}};
a.str.PrintStr();
}