插件符号作为函数 return
Plugin symbol as function return
我 运行 陷入了一种我不理解的 Go 行为。我的想法是导入一个插件,它实现了两个包之外的接口。如果一个结构被 returned 它工作正常,但为了确保它实现了接口,我想 return 一个失败的接口。
接口定义:
package iface
type IPlugin interface{
SayHello(string)
SayGoodby(string)
WhatsYourName() string
}
主程序如下所示:
package main
import (
"plugin"
"plugin_test/iface"
"errors"
"fmt"
)
//go:generate go build -buildmode=plugin -o ./pg/test.so ./pg/test.go
func main(){
path := "pg/test.so"
plug, err := plugin.Open(path)
if err != nil {
panic(err)
}
sym, err := plug.Lookup("Greeter")
if err != nil {
panic(err)
}
var pg iface.IPlugin
pg, ok := sym.(iface.IPlugin)
if !ok {
panic(errors.New("error binding plugin to interface"))
}
fmt.Printf("You're now connected to: %s \n", pg.WhatsYourName())
pg.SayHello("user")
pg.SayGoodby("user")
}
插件(保存在pg/test.go)
package main
import (
"fmt"
"plugin_test/iface"
)
type testpl struct {}
func(pl testpl) SayHello(s string){
fmt.Printf("Plugin says hello to %s \n", s)
}
func(pl testpl) SayGoodby(s string){
fmt.Printf("Plugin says goodby to %s \n", s)
}
func(pl testpl) WhatsYourName() string{
return "my name is Test-Plugin"
}
/* This function works */
func getPlugin() testpl{
return testpl{}
}
/* This function doesn't work */
func getPlugin() iface.IPlugin{
return testpl{}
}
/* This function also doesn't work */
func getPlugin() interface{}{
return testpl{}
}
var Greeter = getPlugin()
我单独尝试了每个 getPlugin
函数。
函数 returning testpl
打印预期输出:
You're now connected to: my name is Test-Plugin
Plugin says hello to user
Plugin says goodby to user
其他功能结束于sym.(iface.IPlugin)
panic: error binding plugin to interface
goroutine 1 [running]:
main.main()
/home/../../../main.go:27 +0x343
exit status 2
有人可以解释为什么这不可能吗?如果在这种情况下不允许您构建插件,那么创建插件不是更容易吗?
你想要的是可能的,但后台有一些东西阻止它工作。
这就是你要从插件中查找一个名为Greeter
的变量。 Plugin.Lookup()
将 return 指向此变量的指针!如果不行,你只能检查它的值,而不能改变它。
您可以通过简单地打印存储在 sym
中的值的类型来验证这一点:
fmt.Printf("%T\n", sym)
在您的第一个案例中 func getPlugin() testpl
,输出将是:
*main.testpl
在第二种情况下 func getPlugin() iface.IPlugin
,输出将是:
*iface.IPlugin
(是的,它是一个接口指针!)
在第三种情况下 func getPlugin() interface{}
,输出将是:
*interface {}
所以你的第一个例子是有效的,因为存储在 sym
中的值是类型 *main.testpl
,它也实现了 iface.IPlugin
(因为 main.testpl
实现了它,所以指针类型)。
回到你的第二个例子:func getPlugin() iface.IPlugin
存储在sym
中的值是*iface.IPlugin
类型。指向接口的指针类型的值从不满足任何接口(空接口除外),因此尝试从 *iface.IPlugin
类型的值 type-assert iface.IPlugin
永远不会成功。您必须键入 assert *iface.IPlugin
类型,之后您可以取消引用以获得类型 iface.IPlugin
的值。它可能看起来像这样:
pgPtr, ok := sym.(*iface.IPlugin)
if !ok {
panic(errors.New("error binding plugin to interface"))
}
pg := *pgPtr
现在一切正常!
为避免此类麻烦和混乱,您可以实现您的插件以公开一个 函数,其中 return 是您 Greeter
:
func Greeter() iface.IPlugin { return testpl{} }
然后当然要去掉 Greeter
全局变量。如果这样做,您可以查找 Greeter
类型的符号:
func() iface.IPlugin
不同之处在于查找函数不需要 plugin
包到 return 指向值的指针,而在变量的情况下它需要。一个简单的函数类型,没有pointer-to-interface-kung-fu。使用它来获取欢迎程序将是:
Greeter, err := p.Lookup("Greeter")
if err != nil {
panic(err)
}
greeterFunc, ok := GetFilter.(func() iface.IPlugin)
if !ok {
panic(errors.New("not of expected type"))
}
greeter := greeterFunc()
// And using it:
fmt.Printf("You're now connected to: %s \n", greeter.WhatsYourName())
greeter.SayHello("user")
greeter.SayGoodby("user")
查看相关/类似问题:go 1.8 plugin use custom interface
我 运行 陷入了一种我不理解的 Go 行为。我的想法是导入一个插件,它实现了两个包之外的接口。如果一个结构被 returned 它工作正常,但为了确保它实现了接口,我想 return 一个失败的接口。
接口定义:
package iface
type IPlugin interface{
SayHello(string)
SayGoodby(string)
WhatsYourName() string
}
主程序如下所示:
package main
import (
"plugin"
"plugin_test/iface"
"errors"
"fmt"
)
//go:generate go build -buildmode=plugin -o ./pg/test.so ./pg/test.go
func main(){
path := "pg/test.so"
plug, err := plugin.Open(path)
if err != nil {
panic(err)
}
sym, err := plug.Lookup("Greeter")
if err != nil {
panic(err)
}
var pg iface.IPlugin
pg, ok := sym.(iface.IPlugin)
if !ok {
panic(errors.New("error binding plugin to interface"))
}
fmt.Printf("You're now connected to: %s \n", pg.WhatsYourName())
pg.SayHello("user")
pg.SayGoodby("user")
}
插件(保存在pg/test.go)
package main
import (
"fmt"
"plugin_test/iface"
)
type testpl struct {}
func(pl testpl) SayHello(s string){
fmt.Printf("Plugin says hello to %s \n", s)
}
func(pl testpl) SayGoodby(s string){
fmt.Printf("Plugin says goodby to %s \n", s)
}
func(pl testpl) WhatsYourName() string{
return "my name is Test-Plugin"
}
/* This function works */
func getPlugin() testpl{
return testpl{}
}
/* This function doesn't work */
func getPlugin() iface.IPlugin{
return testpl{}
}
/* This function also doesn't work */
func getPlugin() interface{}{
return testpl{}
}
var Greeter = getPlugin()
我单独尝试了每个 getPlugin
函数。
函数 returning testpl
打印预期输出:
You're now connected to: my name is Test-Plugin
Plugin says hello to user
Plugin says goodby to user
其他功能结束于sym.(iface.IPlugin)
panic: error binding plugin to interface
goroutine 1 [running]:
main.main()
/home/../../../main.go:27 +0x343
exit status 2
有人可以解释为什么这不可能吗?如果在这种情况下不允许您构建插件,那么创建插件不是更容易吗?
你想要的是可能的,但后台有一些东西阻止它工作。
这就是你要从插件中查找一个名为Greeter
的变量。 Plugin.Lookup()
将 return 指向此变量的指针!如果不行,你只能检查它的值,而不能改变它。
您可以通过简单地打印存储在 sym
中的值的类型来验证这一点:
fmt.Printf("%T\n", sym)
在您的第一个案例中 func getPlugin() testpl
,输出将是:
*main.testpl
在第二种情况下 func getPlugin() iface.IPlugin
,输出将是:
*iface.IPlugin
(是的,它是一个接口指针!)
在第三种情况下 func getPlugin() interface{}
,输出将是:
*interface {}
所以你的第一个例子是有效的,因为存储在 sym
中的值是类型 *main.testpl
,它也实现了 iface.IPlugin
(因为 main.testpl
实现了它,所以指针类型)。
回到你的第二个例子:func getPlugin() iface.IPlugin
存储在sym
中的值是*iface.IPlugin
类型。指向接口的指针类型的值从不满足任何接口(空接口除外),因此尝试从 *iface.IPlugin
类型的值 type-assert iface.IPlugin
永远不会成功。您必须键入 assert *iface.IPlugin
类型,之后您可以取消引用以获得类型 iface.IPlugin
的值。它可能看起来像这样:
pgPtr, ok := sym.(*iface.IPlugin)
if !ok {
panic(errors.New("error binding plugin to interface"))
}
pg := *pgPtr
现在一切正常!
为避免此类麻烦和混乱,您可以实现您的插件以公开一个 函数,其中 return 是您 Greeter
:
func Greeter() iface.IPlugin { return testpl{} }
然后当然要去掉 Greeter
全局变量。如果这样做,您可以查找 Greeter
类型的符号:
func() iface.IPlugin
不同之处在于查找函数不需要 plugin
包到 return 指向值的指针,而在变量的情况下它需要。一个简单的函数类型,没有pointer-to-interface-kung-fu。使用它来获取欢迎程序将是:
Greeter, err := p.Lookup("Greeter")
if err != nil {
panic(err)
}
greeterFunc, ok := GetFilter.(func() iface.IPlugin)
if !ok {
panic(errors.New("not of expected type"))
}
greeter := greeterFunc()
// And using it:
fmt.Printf("You're now connected to: %s \n", greeter.WhatsYourName())
greeter.SayHello("user")
greeter.SayGoodby("user")
查看相关/类似问题:go 1.8 plugin use custom interface