我在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的内容。
我在这里缺少明显的东西吗?
答案 0 :(得分:2)
第一个问题是插件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
查看相关问题:
答案 1 :(得分:1)
您的插件Make方法应该返回一个Sayer对象而不是
type Sayer interface {
Say() string
}
func (t *thingFactory) Make(s string) Sayer {
return New(s)
}