Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Anonymous interface implementation in Golang

In Go, is there a way to satisfy an interface anonymously? It doesn't seem like there is, but this was my best attempt.

(In the 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) } 
like image 332
jocull Avatar asked Jul 11 '15 21:07

jocull


2 Answers

Go uses method sets to declare which methods belong to a type. There is only one way to declare functions with receiver types (methods):

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

Since nested functions are forbidden, there is no way to define a method set on anonymous structs.

The second thing that will not allow this is that methods are read-only. Method values were introduced to allow to pass methods around and use them in goroutines but not to manipulate the method set.

What you can do instead is to provide a ProtoThing and refer to underlying implementations of your anonymous struct (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 } 

This works because by embedding ProtoThing the method set is inherited. Thus the anonymous struct also satisfies the Thing interface.

like image 183
nemo Avatar answered Sep 28 '22 03:09

nemo


Here's neat way to satisfy an interface with an anonymous function.

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

Playground: https://play.golang.org/p/k8_X9g2NYc

nb, it looks like HandlerFunc in http package uses this pattern: https://golang.org/pkg/net/http/#HandlerFunc

edit: Changed type DoThing to DoThingWith for clarity. Updated playground

like image 30
Allen Hamilton Avatar answered Sep 28 '22 04:09

Allen Hamilton