我正在尝试制作几种类型,可以调用相同的函数来执行一些常见操作,而无需为每种类型复制它们 . 我们称这些类型的处理程序 .
我的想法是我可以有一个CreateHandler,一个ListHandler等,以及一个将为这些处理程序执行默认操作的函数,比方说,将“Success”字段设置为true并在处理程序上调用“Execute”函数 . 我保持这些示例简单易读,但在实际情况下会有更常见的操作方式 .
我尝试了3种不同的方法,无济于事:使用基类型并嵌入它,使用类型实现的接口并使用空接口作为参数 .
嵌入的基本类型
package main
import "fmt"
type BaseHandler struct {
Success bool
}
func ( handler *BaseHandler ) Init() {
handler.Success = true
handler.Execute()
}
func ( handler *BaseHandler ) Execute() {
}
// I will have many different types doing the same kind of work,
// with their own specific fields and functions
type MyHandler struct {
BaseHandler
Message string
}
func ( handler *MyHandler ) Execute() {
fmt.Println( "I'm never called" )
}
func main() {
handler := MyHandler{}
handler.Init()
}
这不起作用,因为调用的 Execute
函数是来自 BaseHandler
的函数,而不是 MyHandler
. 如果 Init
方法没有接收器并且将 *BaseHandler
作为参数,则会出现同样的问题 .
接口由类型实现
package main
import "fmt"
type BaseHandler interface {
Execute()
}
func Init( handler BaseHandler ) {
handler.Success = true
handler.Execute()
}
type MyHandler struct {
Success bool
Message string
}
func ( handler *MyHandler ) Execute() {
fmt.Println( "I'm never called" )
}
func main() {
handler := MyHandler{}
Init( handler )
}
由于 Init
函数的第一行,这将无法编译,说 BaseHandler
接口没有 Success
字段 .
空接口作为参数
package main
import "fmt"
func Init( handler interface{} ) {
handler.Success = true
handler.Execute()
}
type MyHandler struct {
Success bool
Message string
}
func ( handler *MyHandler ) Execute() {
fmt.Println( "I'm never called" )
}
func main() {
handler := MyHandler{}
Init( handler )
}
这将无法在 Init
的第一行编译,说 interface{}
没有 Success
字段 . 我不能在那里输入断言,因为它意味着列出可以去那里的所有类型,并且可能有很多 .
问题
所以这是我的问题:你如何编写共享代码,可以设置字段和从类似类型调用函数?
3 回答
handler.Success = true
感觉它属于Execute
. 因此,您可以定义一个接口并在此接口上创建Init
函数,同时在"children"中嵌入接口:游乐场:https://play.golang.org/p/iDo2BQ6N5D .
好像你需要init才能设置成功并执行某些操作 .
TL; DR Heres the playground link https://play.golang.org/p/jflmT-LpJy
因此,使用接口,我将创建以下内容
现在,您希望SetSuccess可以在多种类型中重复使用 . 为此,我将创建一个可嵌入所有类型的结构
自动嵌入这个使您可以访问
SetSuccess
,因此任何具有Execute
并嵌入此结构的结构也将是SuccessableExecutable
.把它放在一起,我们有
尝试嵌入接口:
https://play.golang.org/p/aGZMnuoBh_
这样就可以在基本处理程序中跟踪Success,但是Execute的实际实现可以通过任何类型动态填充(只要它满足该接口) .
就个人而言,我喜欢再向前迈进一步,并将interface-embedding-struct作为另一个接口传递(与嵌入式相同,因为结构会自动实现它嵌入的所有接口,或者作为另一个接口与其他或其他方法一起使用) ) .
另外,一个相关的注意事项:我总是建议将指针传递给接口,这是一个有趣的Go怪癖,存储指针的接口可以访问该存储类型的指针和值接收器方法,但是存储值的接口直接(即使接口在大多数情况下仍然存储指向该值的指针)只能访问值接收器方法 . 例如:https://play.golang.org/p/6qOYhol_y_