REPL是Read-Eval-Print Loop
的缩写,是一种简单的,交互式的编程环境,其中REPL分别指:python
Read。得到用户输入 Eval。对输入求值 Print。打印,输出求值的结果 Loop。循环,能够不断的重复Read-Eval-Printgit
REPL对于学习一门新的编程语言很是有帮助,你能够再这个交互环境里面经过输出快速验证你的理解是否是正确。CPython自带了一个这样的编程环境:github
❯ python3
Python 3.7.1 (default, Dec 13 2018, 22:28:16)
[Clang 10.0.0 (clang-1000.11.45.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 1
>>> a + 2
3
>>> print(a - 1)
0
>>> def b(n):
... return n + 2
...
>>> b(3)
5
复制代码
使用Python开发、DEBUG效率高的一个重要缘由是因为IPython这个工具,相信作过Python开发的同窗都有体会。IPython是一个基于Python Shell的交互式解释器,能够快速验证代码运行结果是否符合预期。它有如下主要特性:golang
import os
后,输入os.
再按Tab就能列出所有方法,在按Tab就会一个个的选择它们,另外能够输入os.p
再按Tab会列出以p开头的所有方法等。固然IPython还有不少不少其余的功能,如历史记录、各类Magic函数、autoreload等扩展,这些对于开发和调试都很是有帮助,能够说是Python工程师必备工具。算法
开始学习Golang后,对于这种REPL编程环境很是渴望,由于它对于初学者友好且对于熟悉Golang很是有帮助。express
一番调研,目前Golang世界中共有6个可用的REPL解释环境:3个终端使用,3个在线编辑,本文分别介绍它们。编程
gomacro是一个具备REPL,Eval,泛型和相似Lisp宏的交互式Go解释器和调试器。bash
先安装它:session
❯ go get -u github.com/cosmos72/gomacro
复制代码
体验一下:app
❯ gomacro
... // 省略一些输出
gomacro> a := 1
gomacro> a
1 // int
gomacro> import "fmt"
gomacro> fmt.Println(a)
1
2 // int
<nil> // error
gomacro> func Add(a, b int) int {
. . . . return a + b
. . . . }
gomacro> Add(1, 2)
3 // int
gomacro> type Comment struct {
. . . . A int
. . . . }
gomacro> c := Comment{}
gomacro> c.A
0 // int
gomacro> :inspect fmt.Printf // 所有支持功能能够输入`:help`回车看到
fmt.Printf = 0x5084730 // func(string, ...interface {}) (int, error) // 查看方法签名
// type ? for inspector help
gomacro> :debug Add(1, 2) // 进入DEBUG模式
// stopped at repl.go:1:1 IP=0, call depth=1. type ? for debugger help
func Add(a, b int) int {
^^^
debug> print a // 打印a的值和类型
1 // int
debug> vars // 查看本地变量
// ----------
a = 1 // int
b = 2 // int
debug> ? // 查看帮助信息
// debugger commands:
backtrace show call stack
env [NAME] show available functions, variables and constants
in current scope, or from imported package NAME
? show this help
help show this help
inspect EXPR inspect expression interactively
kill [EXPR] terminate execution with panic(EXPR)
print EXPR print expression, statement or declaration
list show current source code
continue resume normal execution
finish run until the end of current function
next execute a single statement, skipping functions
step execute a single statement, entering functions
vars show local variables
// abbreviations are allowed if unambiguous. enter repeats last command.
复制代码
整体上的体验就是一个支持基本功能的REPL,支持Tab自动补全(例如输入fmt.Print
按Tab会在fmt.Print
、fmt.Printf
和fmt.Println
以前切换)、调试和简单的查看函数签名,可是不支持语法高亮。
gomacro对于基本的快速验证代码运行结果是够的,可是不能获取获取源代码,看不了对应实现文档。
go-pry对本身的描述是「一个Go的交互式REPL,可以让你在任何执行点放入代码」。官网有一个动态图很是好的说明它的效果:
先安装它:
❯ go get github.com/d4l3k/go-pry
❯ go install -i github.com/d4l3k/go-pry
复制代码
我把它理解为相似于Python里面的IPDB(IPython Debugger),是一个代码命令行调试工具,这个PEPL功能很是有限。体验它一下就能理解了:
❯ go-pry -i="fmt" # 启动后自动导入了fmt包
From /var/folders/x6/vg82csf90dl3mnnqtbb32d580000gn/T/pry130526050/main.go @ line 9 :
4:
5: "fmt"
6: )
7: func main() {
8:
=> 9: pry.Pry()
10: }
11:
[2] go-pry> a := 1
=> 1
[3] go-pry> a + 2
=> 3
[4] go-pry> fmt.Println(a)
1
=> []interface {}{2, interface {}(nil)}
[5] go-pry> func Add (a, b int) int { return a + b}
Error: 1:13: expected '(', found Add <nil>
[6] go-pry> type Comment struct {
Error: 1:30: expected ';', found '(' <nil>
复制代码
在使用中时能够感觉到,它只支持基本的表达式和函数调用,在输出的过程当中会有补全的提示(可是不能自动补全)和函数签名信息。因此它只适合在特定的环境里面调试代码。举个例子,下面这个程序会把终端输入的参数转成整数:
package main
import (
"fmt"
"os"
"strconv"
)
func main() {
args := os.Args
for i := 1; i < len(args); i++ {
ret, err := strconv.Atoi(args[i])
if err != nil {
fmt.Println(err.Error())
} else {
fmt.Println(ret)
}
}
}
复制代码
试一下:
❯ go run example.go 1 2 4
1
2
4
❯ go run example.go 1 3 b
1
3
strconv.Atoi: parsing "b": invalid syntax
复制代码
其实做为开发者一眼就能看出来"b"是不能转换的。借用go-pry能够在对应的位置直接插入(就像项目描述说的那样「可以让你在任何执行点放入代码」):
package main
import (
"fmt"
"os"
"strconv"
"github.com/d4l3k/go-pry/pry"
)
func main() {
args := os.Args
for i := 1; i < len(args); i++ {
ret, err := strconv.Atoi(args[i])
pry.Pry() // 加在了这里,每次循环都会「断点」停下来
if err != nil {
fmt.Println(err.Error())
} else {
fmt.Println(ret)
}
}
}
复制代码
此次咱们再看:
❯ go-pry run exampleWithPry.go 1 3 b
From /Users/xiaoxi/strconv.code/repl/goPry/exampleWithPry.go @ line 15 :
10:
11: func main() {
12: args := os.Args
13: for i := 1; i < len(args); i++ {
14: ret, err := strconv.Atoi(args[i])
=> 15: pry.Pry()
16: if err != nil {
17: fmt.Println(err.Error())
18: } else {
19: fmt.Println(ret)
20: }
[13] go-pry> ret
=> 1
[14] go-pry> err
=> <nil>
[15] go-pry> args
=> []string{"/var/folders/x6/vg82csf90dl3mnnqtbb32d580000gn/T/go-build624971651/b001/exe/exampleWithPry", "1", "3", "b"}
[16] go-pry> // Ctrl+D 退出当前循环
1
[16] go-pry> // 继续退出一次循环
3
From /Users/xiaoxi/strconv.code/repl/goPry/exampleWithPry.go @ line 15 :
10:
11: func main() { []string
12: args := os.Args
13: for i := 1; i < len(args); i++ {
14: ret, err := strconv.Atoi(args[i])
=> 15: pry.Pry()
16: if err != nil {
17: fmt.Println(err.Error())
18: } else {
19: fmt.Println(ret)
20: }
[16] go-pry> ret
=> 0
[17] go-pry> err
=> strconv.NumError{Func:"Atoi", Num:"b", Err:(*errors.errorString)(0xc000064010)}
[18] go-pry> args[i]
=> "b"
[19] go-pry> strconv.Atoi("b")
=> []interface {}{0, (*strconv.NumError)(0xc0003c7b30)}
复制代码
这样就定位到抛错的这一次循环中的各个本地环境变量,知道上下文是什么能够在这个交互环境下试验,就很容易知道问题出在哪里了
gore是另一个Go REPL,支持行编辑、自动补全等特性。官网有一个动态图能够体验到它:
❯ GO111MODULE=off go get -u github.com/motemen/gore/cmd/gore
# 若是但愿支持自动补全和更好的输出效果须要安装:
GO111MODULE=off go get -u github.com/mdempsky/gocode
GO111MODULE=off go get -u github.com/k0kubun/pp # 或者用github.com/davecgh/go-spew/spew
复制代码
而后体验它:
❯ gore
gore version 0.4.1 :help for help
gore> a := 1
1
gore> a + 2
3
gore> func Add(a, b int) int { return a + b }
gore> Add(1, 2)
3
gore> type Comment struct {
..... B string
..... }
gore> c := Comment{}
main.Comment{
B: "",
}
gore> c.B
""
gore> :import fmt
gore> fmt.Println("Hello")
Hello
6
nil
gore> fmt.Println("Hello") // 居然有BUG!! 多执行一次多重复输出一行
Hello
Hello
6
nil
gore> :help
:import <package> import a package
:type <expr> print the type of expression
:print print current source
:write [<file>] write out current source
:clear clear the codes
:doc <expr or pkg> show documentation
:help show this help
:quit quit the session
gore> :type Add
func(a int, b int) int
gore> :type a
int
gore> :print Add
package main
import (
"github.com/k0kubun/pp"
"fmt"
)
func __gore_p(xx ...interface{}) {
for _, x := range xx {
pp.Println(x)
}
}
func main() {
a := 1
_ = Add(1, 2)
type Comment struct{ B string }
c := Comment{}
_, _ = fmt.Println("Hello")
_, _ = fmt.Println("Hello")
}
func Add(a, b int) int { return a + b }
gore> :doc fmt.Println
func Println(a ...interface{}) (n int, err error)
Println formats using the default formats for its operands and writes to
standard output. Spaces are always added between operands and a newline is
appended. It returns the number of bytes written and any write error
encountered.
复制代码
能够感觉到,虽然gore不支持写代码时高亮,可是输出的结果带了颜色还算体验好一些。另外它支持自动补全、查看签名、类型和对应文档,还能看在gore交互环境中的函数的源码(用:print
),不过导入包的方法略奇怪(要用:import
),且有fmt模块打印相关的BUG(有点不该该了)。
但整体上gore是上述三个库中效果最好的REPL了!
接着介绍Web端的REPL工具。Repl.it
是一个云端的在线编辑器和IDE,它支持所有主流的编程语言,包括Go。在这个Web端的页面里面能够编辑代码并执行,Web端也会输出结果。它支持显示补全列表和语法高亮,且支持静态检查,直接在对应行显示错误缘由。另外能够生成短链接方便分享出去,很是适合快速验证、教学和演示等用途。
lgo和gophernotes都是Golang语言的Jupyter Notebook内核,实现了在Jupyter Notebook(原来的IPython Notebook)上编写Golang代码并执行。
Jupyter Notebook是一个交互式笔记本应用,是一个Web应用,算法和数据分析工程师用的比较多。
lgo和gophernotes具体安装就不演示了,我的以为仍是在终端REPL更好用。有兴趣的能够看一下gophernotes项目下的动态图看效果:
原文连接: strconv.com/posts/go-re…
完整代码能够在这个地址找到。