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…
完整代碼能夠在這個地址找到。