golang插件可以用于工厂功能吗?

golang插件可以用于工厂功能吗?,go,plugins,Go,Plugins,我在golang插件模块中有以下代码: 加油 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

我在golang插件模块中有以下代码:

加油

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对象并在另一个程序中使用:

梅因,加油

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
}
主程序包
进口(
“fmt”
“插件”
)
func main(){
p、 err:=plugin.Open(“../plug/plug.so”)
如果错误!=零{
恐慌(错误)
}
符号,err:=p.Lookup(“东西”)
如果错误!=零{
恐慌(错误)
}
事物:=符号
fmt.Println(thing.Say())

symbol,err=p.Lookup(“ThingFactory”)/您的plugin Make方法应该返回一个Sayer对象,而不是thing

type Sayer interface {
    Say() string
}
func (t *thingFactory) Make(s string) Sayer {
    return New(s)
}

第一个问题是,在您的插件
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
接口“外包”到它自己的包中,并在插件和主应用程序中使用这个通用的共享包

让我们创建一个新包,称之为
子播放

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
见相关问题:


我没有断言它是
Sayer
-我断言了
GetSayer
-工厂类型。您定义为
factory
的接口与我定义的接口相同,只是我称它为
GetSayer
。此外,在插件代码中放入另一个接口,意味着接口转换会导致指向int的指针erface problems.@domoarigato GetSayer的签名和plugin的Make方法是不同的。更改plugin方法以返回Sayer这就是问题所在,它们实际上没有什么不同。
thingFactory
有一个
Make
方法,它返回一个
东西,编译器识别出它是
Sayer
,因此
ingFactory
实现了
GetSayer
Sayer
接口在主机代码中,而不是插件代码中,并且在插件代码中放置了一个不同的接口,该接口也恰好被称为
Sayer
,返回该接口不会改变任何情况(我确实尝试过)除了它确实会导致类型转换中的*接口出现问题。尝试过,抱歉,但不起作用。它仍然无法识别该插件。thingFactory是主机。GetSayer:缺少方法使-出现相同的问题。谢谢-我确信这应该是可能的,但第三个包“外包”不明显。我做了一些搜索,但不幸的是,在野外仍然没有大量的插件使用。