Yaegi
Yaegi 是另一个优雅的 Go 解释器。它在 Go 运行时的基础上,在嵌入式解释器或交互式 shell 中支持可执行的 Go 脚本和插件。
特性
- 完全支持 Go 规范
- 用纯 Go 语言编写,只使用标准库。
- 简单的解释器 API:New(), Eval(), Use()
- 在任何地方都可以使用 Go
- 所有的 Go 和运行时资源都可以从脚本中访问(带控制)。
- 安全性:默认情况下既不使用也不导出不安全和 syscall 包。
- 支持 Go 1.13和 Go 1.14(最新的两个主要版本)。
安装
Go 包
import "github.com/traefik/yaegi/interp"
命令行可执行文件
go get -u github.com/traefik/yaegi/cmd/yaegi
请注意,你可以使用 rlwrap(用你喜欢的包管理器安装),并在你的 ~/.bashrc 中用 alias yaegi='rlwrap yaegi' 来别名 yaegi 命令,以获得历史和命令行版本。
CI 集成
curl -sfL https://raw.githubusercontent.com/traefik/yaegi/master/install.sh | bash -s -- -b $GOPATH/bin v0.9.0
用法
作为一个嵌入式解释器
用 New() 创建一个解释器,用 Eval() 运行 Go 代码。
package main import ( "github.com/traefik/yaegi/interp" "github.com/traefik/yaegi/stdlib" ) func main() { i := interp.New(interp.Options{}) i.Use(stdlib.Symbols) _, err := i.Eval(`import "fmt"`) if err != nil { panic(err) } _, err = i.Eval(`fmt.Println("Hello Yaegi")`) if err != nil { panic(err) } }
作为一个动态扩展框架
下面的程序除了 bar() 被解释外,其他都是提前编译好的,步骤如下。
- 使用 i.Eval(src) 在解释器的上下文中评估脚本。
- 使用 v, err := i.Eval("foo.Bar") 从解释器上下文中获取符号,作为 reflect.Value。
- 应用 Interface() 方法和类型断言将 v 转换为 bar,就像编译时一样
package main import "github.com/traefik/yaegi/interp" const src = `package foo func Bar(s string) string { return s + "-Foo" }` func main() { i := interp.New(interp.Options{}) _, err := i.Eval(src) if err != nil { panic(err) } v, err := i.Eval("foo.Bar") if err != nil { panic(err) } bar := v.Interface().(func(string) string) r := bar("Kung") println(r) }
作为一个命令行解释器
Yaegi 命令可以运行一个交互式的 Read-Eval-Print-Loop。
$ yaegi > 1 + 2 3 > import "fmt" > fmt.Println("Hello World") Hello World >
或者解释 Go 文件
$ yaegi cmd/yaegi/yaegi.go >
或为 Go 脚本中的 shebang 行。
$ cat /tmp/test #!/usr/bin/env yaegi package main import "fmt" func main() { fmt.Println("test") } $ ls -la /tmp/test -rwxr-xr-x 1 dow184 dow184 93 Jan 6 13:38 /tmp/test $ /tmp/test test
文档
关于 Yaegi 命令和库的文档可以在 godoc.org 找到。
限制
- 除了已知的 bugs 应该会在短期内修复,还有一些限制没有计划很快解决。
- 不支持汇编文件(.s)。
- 不支持调用 C 代码(没有虚拟的 "C" 包)。
- 不能动态添加从预编译代码中使用的接口,因为需要预编译接口封装。
- 用 reflect 来表示类型,用 %T 来打印值,在编译模式和解释模式之间可能会有不同的结果。
- 解释计算密集型代码很可能仍然比编译模式慢很多。
贡献
贡献指南。
许可证
(The first version translated by vz on 2020.09.26)