Внедрение анонимного интерфейса в Golang
В Go, существует ли способ анонимного интерфейса? Кажется, что нет, но это была моя лучшая попытка.
(На Игровая площадка)
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 использует методы , чтобы объявить, какие методы принадлежат типу. Существует только один способ объявить функции с типами приемников (методы):
func (v T) methodName(...) ... { }
Так как вложенные функции запрещены, невозможно определить метод, установленный для анонимных структур.
Вторая вещь, которая не позволит этого, заключается в том, что методы доступны только для чтения. Значения метода, чтобы позволить передавать методы и использовать их в goroutines, но не манипулировать набором методов.
Вместо этого вы можете предоставить ProtoThing и обратиться к базовым реализациям вашей анонимной структуры (в игре):
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
.
Ответ 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, похоже, что HandlerFunc в http-пакете использует этот шаблон: https://golang.org/pkg/net/http/#HandlerFunc
edit: Изменен тип DoThing для DoThingWith для ясности. Обновленная игровая площадка
Ответ 3
Вы не можете создавать структуру с помощью методов, их нужно объявлять как функции, но в функциях Go являются "гражданами первого класса", поэтому они могут быть значениями полей, как в JavaScript (но набраны).
Вы можете создать общую структуру, которая принимает функциональные поля для реализации интерфейса:
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)
}