go anonymous-types

Implementación de interfaz anónima en Golang



anonymous-types (3)

En Go, ¿hay alguna forma de satisfacer una interfaz de forma anónima? No parece que haya, pero este fue mi mejor intento.

(En el 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) }


Esta es una buena manera de satisfacer una interfaz con una función anónima.

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?") }))

Área de juegos: https://play.golang.org/p/k8_X9g2NYc

nb, parece que HandlerFunc en el paquete http usa este patrón: https://golang.org/pkg/net/http/#HandlerFunc

Editar: Se ha cambiado el tipo DoThing to DoThingWith para mayor claridad. Parque infantil actualizado


Go utiliza conjuntos de métodos para declarar qué métodos pertenecen a un tipo. Solo hay una forma de declarar funciones con tipos de receptor (métodos):

func (v T) methodName(...) ... { }

Como las funciones anidadas están prohibidas, no hay forma de definir un conjunto de métodos en estructuras anónimas.

La segunda cosa que no permitirá esto es que los métodos son de solo lectura. Los valores de los métodos se introdujeron para permitir pasar métodos y usarlos en goroutines, pero no para manipular el conjunto de métodos.

Lo que puede hacer en su lugar es proporcionar un ProtoThing y referirse a las implementaciones subyacentes de su estructura anónima ( en juego ):

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 }

Esto funciona porque al incrustar ProtoThing el conjunto de métodos se hereda. Por lo tanto, la estructura anónima también satisface la interfaz Thing .


No puede crear una instancia de una estructura con métodos, deben declararse como funciones, pero en Go las funciones son "ciudadanos de primera clase", por lo que pueden ser valores de campo como en JavaScript (pero escritos).

Puede hacer una estructura genérica que acepte campos de función para implementar la interfaz:

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) }