2015-07-11 1151 views
23

在Go中,有沒有一種方法可以匿名滿足接口?它似乎並不存在,但這是我最好的嘗試。Golang中的匿名接口實現

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

回答

27

Go使用method sets聲明哪些方法屬於一個類型。只有一個聲明與接收器類型(方法)的功能的方法:

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

由於嵌套函數被禁止,也沒有辦法來定義上匿名結構設置的方法。

第二件事不會允許這是方法是隻讀的。引入了Method values以允許傳遞方法並在goroutine中使用它們,但不用於操作方法集。

你可以做的反而是提供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接口。

+1

這實在是真棒,我喜歡它是如何半結構化的。嵌入是非常整潔。 – jocull

+0

起初我讀過的部分「不可能的」,但後來回來了,卻一直運行它!好一個! –

8

這裏是爲了滿足一個匿名函數的接口非常簡潔的方式。

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

編輯:更改類型DoThing到DoThingWith的清晰度。更新操場

+0

嘿,那真的很乾淨!幹得不錯! – jocull

0

無法實例與方法結構,它們需要被聲明爲功能,但是在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) 
}