我知道可以查找导出的 go-plugin 符号并将它们键入 assert 到interface 中。但是,我想知道是否有办法将它们输入到结构中,例如。有没有办法做到这一点?
例如:
插件
package main
type Person struct {
Name string
}
var (
P = Person{
Name: "Emma",
}
)
Run Code Online (Sandbox Code Playgroud)
应用程序
package main
import (
"fmt"
"plugin"
"os"
)
func main() {
plug, err := plugin.Open("./plugin.so")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
sym, err := plug.Lookup("P")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
var p Person
p, ok := sym.(Person)
if !ok {
fmt.Println("Wrong symbol type")
os.Exit(1)
}
fmt.Println(p.Name)
}
Run Code Online (Sandbox Code Playgroud)
符号 P 是Person,在调用 plug.Lookup时找到。但是,我无法在Person 中键入断言 P ,我收到执行时间错误。在这个例子中,“错误的符号类型”。
有没有办法实现这一点,或者在插件和应用程序之间共享数据的唯一方法是使用接口?
谢谢。
main包中定义的标识符不能从其他包中引用,因此从插件导出的标识符不能与您在主应用程序中的类型相同。即使您Person在插件文件和主应用程序中都复制了类型,类型断言也会失败,因为它们的类型不同!
但是可以在单独的包中定义类型,并在插件和主应用程序中使用相同的包。然后你可以从你从插件中查找的符号中输入 assert 这种类型。
看这个例子:
在自己的包中定义的单独类型:
package filter
type Filter struct {
Name string
Age int
}
Run Code Online (Sandbox Code Playgroud)
插件代码:
package main
import (
"play/filter"
)
var MyFilter = filter.Filter{
Name: "Bob",
Age: 21,
}
func CreateFilter() filter.Filter {
return filter.Filter{
Name: "Bob",
Age: 21,
}
}
Run Code Online (Sandbox Code Playgroud)
主要应用程序:
package main
import (
"fmt"
"log"
"os"
"play/filter"
"plugin"
)
func main() {
p, err := plugin.Open("plugin.so")
if err != nil {
log.Fatal(err)
}
mf, err := p.Lookup("MyFilter")
if err != nil {
log.Fatal(err)
}
f, ok := mf.(*filter.Filter)
if !ok {
log.Fatal("Wrong symbol type")
}
fmt.Printf("%+v\n", f)
}
Run Code Online (Sandbox Code Playgroud)
运行主应用程序,输出为:
&{Name:Bob Age:21}
Run Code Online (Sandbox Code Playgroud)
你可能会注意到插件中导出的标识符MyFilter是一个非指针类型的变量,但我们从导出的符号中类型断言了一个指针类型。这是因为如果你查找一个变量,你会得到一个指向它的指针,否则你不能修改变量的值,你只能修改副本。这在这个答案中有详细说明:插件符号作为函数返回
如果我们查找插件导出的其他符号,则情况并非如此:CreateFilter()返回非指针类型值的函数filter.Filter:
cf, err := p.Lookup("CreateFilter")
if err != nil {
log.Fatal(err)
}
createFilter, ok := cf.(func() filter.Filter)
if !ok {
log.Fatal("Wrong function type")
}
f2 := createFilter()
fmt.Printf("%+v\n", f2)
Run Code Online (Sandbox Code Playgroud)
运行此代码,输出将是:
{Name:Bob Age:21}
Run Code Online (Sandbox Code Playgroud)
查看相关问题:go 1.8 plugin use custom interface
还要注意的是,如果更改了filter插件和主应用程序常用的包,则还必须重新构建插件。尝试在不重建插件的情况下运行应用程序将导致plugin.Open()调用期间出错。有关详细信息,请参阅Go 插件依赖项如何工作?