Golang 中的匿名接口实现
Posted
技术标签:
【中文标题】Golang 中的匿名接口实现【英文标题】:Anonymous interface implementation in Golang 【发布时间】:2015-09-30 11:00:32 【问题描述】:在 Go 中,有没有办法匿名满足接口?好像没有,但这是我最好的尝试。
(在Playground)
package main
import "fmt"
type Thing interface
Item() float64
SetItem(float64)
func newThing() Thing
item := 0.0
return struct
Item (func() float64)
SetItem (func(float64))
Item: func() float64 return item ,
SetItem: func(x float64) item = x ,
func main()
thing := newThing()
fmt.Println("Hello, playground")
fmt.Println(thing)
【问题讨论】:
【参考方案1】:Go 使用method sets 来声明哪些方法属于一个类型。只有一种方法可以声明具有接收器类型(方法)的函数:
func (v T) methodName(...) ...
由于禁止嵌套函数,因此无法在匿名结构上定义方法集。
不允许这样做的第二件事是方法是只读的。引入Method values 是为了允许传递方法并在 goroutines 中使用它们,但不能操作方法集。
您可以做的是提供一个 ProtoThing 并引用您的匿名结构 (on play) 的底层实现:
type ProtoThing struct
itemMethod func() float64
setItemMethod func(float64)
func (t ProtoThing) Item() float64 return t.itemMethod()
func (t ProtoThing) SetItem(x float64) t.setItemMethod(x)
// ...
t := struct ProtoThing
t.itemMethod = func() float64 return 2.0
t.setItemMethod = func(x float64) item = x
这是有效的,因为通过嵌入 ProtoThing
方法集被继承。因此匿名结构也满足Thing
接口。
【讨论】:
这真是太棒了,我喜欢它是半结构化的。嵌入真的很整洁。 起初我读过“不可能”的部分,但后来回来并实际运行了它!不错! @nemo 为什么 ProtoThing 是一个结构,而不是一个接口? @EdgarAroutiounian 问题是关于 Go 中的一个构造,它可以匿名满足接口(在本例中为Thing
),即不声明命名类型。 ProtoThing
是一个构造,它允许您满足 Thing
接口但交换方法的功能。
此时ProtoThing
感觉和OOP中的抽象类一样【参考方案2】:
这是用匿名函数满足接口的好方法。
type Thinger interface
DoThing()
type DoThingWith func()
// Satisfy Thinger interface.
// So we can now pass an anonymous function using DoThingWith,
// which implements Thinger.
func (thing DoThingWith) DoThing()
// delegate to the anonymous function
thing()
type App struct
func (a App) DoThing(f Thinger)
f.DoThing()
//...Somewhere else in your code:
app := App
// Here we use an anonymous function which satisfies the interface
// The trick here is to convert the anonymous function to the DoThingWith type
// which delegates to the anonymous function
app.DoThing(DoThingWith(func()
fmt.Println("Hey interface, are you satisfied?")
))
游乐场:https://play.golang.org/p/k8_X9g2NYc
nb,看起来 http 包中的 HandlerFunc 使用了这种模式:https://golang.org/pkg/net/http/#HandlerFunc
编辑:为了清楚起见,将类型 DoThing 更改为 DoThingWith。更新游乐场
【讨论】:
【参考方案3】:你不能用方法来实例化结构,它们需要被声明为函数,但在 Go 中,函数是“一等公民”,所以它们可以像 javascript 中一样是字段值(但需要类型化)。
您可以制作一个接受 func 字段的通用结构来实现接口:
package main
import "fmt"
type Thing interface
Item() float64
SetItem(float64)
// Implements Thing interface
type thingImpl struct
item func() float64
setItem func(float64)
func (i thingImpl) Item() float64 return i.item()
func (i thingImpl) SetItem(v float64) i.setItem(v)
func newThing() Thing
item := 0.0
return thingImpl
item: func() float64 return item ,
setItem: func(x float64) item = x ,
func main()
thing := newThing()
fmt.Println("Hello, playground")
fmt.Println(thing)
【讨论】:
【参考方案4】:当我研究典型的 http 中间件实现如何返回 http.Handler
接口而不为它返回的匿名函数定义 ServeHTTP
方法时,我来到这里:
func LoggingMiddleware(next http.Handler) http.Handler
fn := func(w http.ResponseWriter, r *http.Request)
log.Println(r.Method, r.URL.String())
next.ServeHTTP(w, r)
return http.HandlerFunc(fn)
这里将匿名函数转换为HandlerFunc
类型以满足接口要求:http.HandlerFunc(fn)
尽管匿名函数并没有通过实现 ServeHTTP
方法直接实现 Handler
interface 本身,但它转换为的 HandlerFunc type 确实实现了 ServeHTTP
方法。
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request)
f(w, r)
这是一个精简的操场示例:https://play.golang.org/p/JX0hrcXyj6Q
package main
import (
"fmt"
)
type Walker interface
Walk() // interface to be fulfilled by anonymous function
type WalkerFunc func()
// Walk method satisfies Walker interface
func (wf WalkerFunc) Walk()
fmt.Println("start walking")
wf()
fmt.Printf("stop walking\n\n")
func main()
// use type conversion to convert anonymous function to WalkerFunc type, satisfying Walker interface
WalkerFunc(func() fmt.Println("chew gum") ).Walk()
WalkerFunc(func() fmt.Println("smell roses") ).Walk()
【讨论】:
以上是关于Golang 中的匿名接口实现的主要内容,如果未能解决你的问题,请参考以下文章