Подтвердить что ты не робот

Внедрение анонимного интерфейса в 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)
}
4b9b3361

Ответ 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)
}