我遇到了我不了解的Go行为。我的想法是导入一个插件,该插件实现了两个软件包都没有的接口。如果返回一个结构,它可以正常工作,但是要确保它实现了该接口,我想返回一个失败的接口。
接口定义:
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
功能。
返回的函数将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()
将返回一个指向该变量的指针!如果不能,则只能检查其值,但不能更改它。
您可以通过简单地打印存储在中的值的类型来验证这一点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
。指向接口的指针类型的值永远不会满足任何接口(空接口除外),因此尝试从type
iface.IPlugin
值进行类型断言*iface.IPlugin
将永远不会成功。您必须输入assert
*iface.IPlugin
type,然后可以对其进行引用以获取type的值iface.IPlugin
。它可能看起来像这样:
pgPtr, ok := sym.(*iface.IPlugin)
if !ok {
panic(errors.New("error binding plugin to interface"))
}
pg := *pgPtr
现在一切都按预期工作!
为避免此类麻烦和混乱,您可以实现插件以公开返回以下内容的 函数Greeter
:
func Greeter() iface.IPlugin { return testpl{} }
然后Greeter
当然要摆脱全局变量。如果这样做,您可以查找以下Greeter
类型的符号:
func() iface.IPlugin
区别在于查找函数不需要plugin
包返回指向该值的指针,而对于变量则需要。简单的函数类型,没有指向接口的功夫指针。用它来获得迎宾员将是:
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")
上一章展示了 Lisp "把函数作为参数传递" 的能力,它开阔了我们进行抽象的思路。我们对函数能做的事情越多,就越能充分利用这些思想方法。如果能定义一种函数,让它产生并返回新的函数,那就可以成倍放大那些以函数作为参数的实用工具的威力。 这一章要介绍的实用工具就被用来操作函数。要是把它们中的多数写成宏,让这些宏来操纵表达式会显得更自然一些,至少在 Common Lisp 里是这样的。在第 15 章会
如果指针类型作为函数参数,修改形参会影响实参 不能将函数内的指向局部变量的指针作为返回值,函数结束指向空间会被释放 可以将函数内的局部变量作为返回值,本质是拷贝一份
我使用的是我的代码中有两个可观察的对象 观察值不是来自请求,而是来自 我需要根据这个逻辑将序列组合/转换成一个单一的可观察值: 如果序列,或,-需要返回新的可观察的否则需要返回 我试图使用来实现: 但问题是我的
以下是MathML中可用的函数符号列表。 MathML符号 HTML实体 Hex代码 描述 ⋅ ⋅ ⋅ 指定点积 ⨯ ✗ ⨯ 指定交叉产品 ‖ | ‖ 指定范数(幅度)条 ⟨ ⟨ ⟨ 指定左尖括号 ⟩ ⟩ ⟩ 指定直角括号 ∘ ∘ ∘ 指定功能组成 → → → 指定一般函数映射 ↦ ↦ ↦ 指定具体的函数映射
问题内容: 是否可以获取从调用范围返回函数的行号? 例: 我认为这是不可能的,因为它应该已经从堆栈中删除了,但是也许它仍然被缓存在某个地方? 用例是我有一个HTTP处理程序,我想记录返回错误的行和文件名,而不必乱扔代码。 问题答案: AFAIK,不可能自动获取执行最后一次返回的行。 但是,有了一个小帮手,您可以拥有: 操场 输出:
我正在尝试从16位架构中读取二进制16位机器指令(其确切性质在这里无关紧要),并将它们打印回十六进制值。在C中,我发现这很简单,方法是使用函数将16位读入。 我想我会尝试在Rust中复制。如果我能提前知道被读入的变量的确切大小,这似乎是相当微不足道的,而且我专门为16位工作。 我决定尝试使函数在各种内置无符号整数类型上通用。为此,我使用Num crate中的一些特征提出了以下函数: 问题是当我在m