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)
}
Goは method sets を使用して、どのメソッドが型に属するかを宣言します。レシーバータイプ(メソッド)で関数を宣言する方法は1つしかありません。
func (v T) methodName(...) ... { }
ネストされた関数は禁止されているため、匿名の構造体に設定されたメソッドを定義する方法はありません。
これを許可しない2番目のことは、メソッドが読み取り専用であることです。 メソッド値 は、メソッドを渡してゴルーチンで使用できるようにするために導入されましたが、メソッドセットを操作することはできません。
代わりにできることは、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
インターフェイスも満たします。
以下は、匿名関数を使用してインターフェイスを満たすための適切な方法です。
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
edit:明確にするために、タイプDoThingをDoThingWithに変更しました。更新された遊び場
メソッドを使用して構造体をインスタンス化することはできません。関数として宣言する必要がありますが、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)
}