Можно ли использовать плагины golang для заводских функций? - PullRequest
0 голосов
/ 23 декабря 2018

У меня есть следующий код в модуле плагина golang:

plug.go

package main

import "fmt"

var (
    Thing        = New("first thing")
    ThingFactory = thingFactory{}
)

type thing struct {
    i int
    s string
}

func New(s string) thing {
    return thing{s: s}
}

func (t *thing) Say() string {
    t.i++
    return fmt.Sprintf("%s - %d", t.s, t.i)
}

type thingFactory struct{}

func (t thingFactory) Make(s string) thing {
    return New(s)
}

он скомпилирован как объект .so и используется в другой программе:

main.go

package main

import (
    "fmt"
    "plugin"
)

func main() {
    p, err := plugin.Open("../plug/plug.so")
    if err != nil {
        panic(err)
    }
    symbol, err := p.Lookup("Thing")
    if err != nil {
        panic(err)
    }
    thing := symbol.(Sayer)
    fmt.Println(thing.Say())

    symbol, err = p.Lookup("ThingFactory") // <-problems start here
    if err != nil {
        panic(err)
    }
    factory := symbol.(GetSayer)

    madeThing := factory.Make("how about me?")
    fmt.Println(madeThing.Say())
    fmt.Println(madeThing.Say())
}

type Sayer interface {
    Say() string
}

type GetSayer interface {
    Make(string) Sayer
}

Я могу найти Thing и вызвать Say(), но второе преобразование интерфейса паникует:

first thing - 1 panic: interface conversion: *main.thingFactory is not main.GetSayer: missing method Make

, хотя среда выполнения распознает первый символ как Sayer, но не распознает, что thingFactory явно имеет метод Make (), который должен возвращать что-то, что также является Sayer.

Я что-то упускаю здесь очевидное?

Ответы [ 2 ]

0 голосов
/ 23 декабря 2018

Первая проблема заключается в том, что в вашем плагине thingFactory (точнее *thingfactory) нет метода, описанного в интерфейсе GetSayer вашего основного приложения:

Make(string) Sayer

У вас есть:

Make(string) thing

Итак (сначала) вы должны изменить thingFactory.Make() на это:

type Sayer interface {
    Say() string
}

func (t thingFactory) Make(s string) Sayer {
    th := New(s)
    return &th
}

После этого все равно не будет работать.И причина этого в том, что тип Sayer плагина не идентичен типу Sayer вашего основного приложения.Но они должны быть одинаковыми для реализации интерфейса GetSayer вашего основного приложения.

Одним из решений является «передача» интерфейса Sayer на свой пакет и использование этого общего общего пакета вплагин и в основном приложении.

Давайте создадим новый пакет, назовите его subplay:

package subplay

type Sayer interface {
    Say() string
}

Импортируйте этот пакет и используйте его в плагине:

package main

import (
    "fmt"
    "path/to/subplay"
)

var (
    Thing        = New("first thing")
    ThingFactory = thingFactory{}
)

type thing struct {
    i int
    s string
}

func New(s string) thing {
    return thing{s: s}
}

func (t *thing) Say() string {
    t.i++
    return fmt.Sprintf("%s - %d", t.s, t.i)
}

type thingFactory struct{}

func (t thingFactory) Make(s string) subplay.Sayer {
    th := New(s)
    return &th
}

А также импортируйте и используйте его в основном приложении:

package main

import (
    "fmt"
    "path/to/subplay"
    "plugin"
)

func main() {
    p, err := plugin.Open("../plug/plug.so")
    if err != nil {
        panic(err)
    }
    symbol, err := p.Lookup("Thing")
    if err != nil {
        panic(err)
    }
    thing := symbol.(subplay.Sayer)
    fmt.Println(thing.Say())

    symbol, err = p.Lookup("ThingFactory")
    if err != nil {
        panic(err)
    }
    factory := symbol.(GetSayer)

    madeThing := factory.Make("how about me?")
    fmt.Println(madeThing.Say())
    fmt.Println(madeThing.Say())
}

type GetSayer interface {
    Make(string) subplay.Sayer
}

Теперь это будет работать, и будет вывод:

first thing - 1
how about me? - 1
how about me? - 2

См. Связанные вопросы:

Плагин Go 1.8 использует пользовательский интерфейс

Как работают зависимости плагина Go?

0 голосов
/ 23 декабря 2018

Ваш плагин Make метод должен возвращать объект Sayer, а не вещь

type Sayer interface {
    Say() string
}
func (t *thingFactory) Make(s string) Sayer {
    return New(s)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...