是否可以在 go 插件和应用程序之间共享自定义数据类型?



我知道可以查找导出的go-plugin符号并将其键入到界面中。但是,我想知道是否有办法将它们键入到结构中。有没有办法做到这一点?

例如:

插件.go

package main
type Person struct {
Name string
}
var (
P = Person{
Name: "Emma",
}
)

app.go

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) 
}

符号 P,即,在插入时找到。调用查找。但是,我无法将 P 键入到个人中,我收到执行时间错误。在此示例中,"错误的符号类型"。

有没有办法实现这一点,或者在插件和应用程序之间共享数据的唯一方法是使用接口?

谢谢。

main包中定义的标识符不能从其他包中引用,因此从插件导出的标识符不能与您在主应用程序中的类型相同。即使您在插件的文件和主应用程序中复制Person类型,类型断言也会失败,因为它们不是同一类型!

但是可以在单独的包中定义类型,并在插件和主应用程序中使用相同的包。然后,您可以从从插件中查找的符号中键入断言此类型。

请参阅此示例:

在其自己的包中定义的单独类型:

package filter
type Filter struct {
Name string
Age  int
}

插件代码:

package main
import (
"play/filter"
)
var MyFilter = filter.Filter{
Name: "Bob",
Age:  21,
}
func CreateFilter() filter.Filter {
return filter.Filter{
Name: "Bob",
Age:  21,
}
}

主应用程序:

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("%+vn", f)
}

运行主应用,输出为:

&{Name:Bob Age:21}

您可能会注意到,插件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("%+vn", f2)

运行此代码,输出将为:

{Name:Bob Age:21}

查看相关问题: go 1.8 插件使用自定义界面

另请注意,如果您更改插件和主应用程序常用的filter包,您还必须重建插件。尝试在不重新构建插件的情况下运行应用程序将导致在plugin.Open()调用期间出错。有关详细信息,请参阅 Go 插件依赖项如何工作?

最新更新