Golang語言中的REPL庫

REPL

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
複製代碼

IPython

使用Python開發、DEBUG效率高的一個重要緣由是因爲IPython這個工具,相信作過Python開發的同窗都有體會。IPython是一個基於Python Shell的交互式解釋器,能夠快速驗證代碼運行結果是否符合預期。它有如下主要特性:golang

  1. Tab自動補全。能夠用Tab對變量、函數、方法等自動補全,好比import os後,輸入os.再按Tab就能列出所有方法,在按Tab就會一個個的選擇它們,另外能夠輸入os.p再按Tab會列出以p開頭的所有方法等。
  2. 能快速得到模塊/函數/類的信息,如參數、文檔、原始代碼等。有時候忘記方法名字或者簽名能夠直接在IPython裏面得到對應信息,甚至能夠看到原始代碼,這很是方便。
  3. 支持Python語法高亮。不用再面對純白色的一大片代碼了。

固然IPython還有不少不少其餘的功能,如歷史記錄、各類Magic函數、autoreload等擴展,這些對於開發和調試都很是有幫助,能夠說是Python工程師必備工具。算法

開始學習Golang後,對於這種REPL編程環境很是渴望,由於它對於初學者友好且對於熟悉Golang很是有幫助。express

一番調研,目前Golang世界中共有6個可用的REPL解釋環境:3個終端使用,3個在線編輯,本文分別介紹它們。編程

gomacro

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.Printfmt.Printffmt.Println以前切換)、調試和簡單的查看函數簽名,可是不支持語法高亮。

gomacro對於基本的快速驗證代碼運行結果是夠的,可是不能獲取獲取源代碼,看不了對應實現文檔。

go-pry

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

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了!

Repl.it

接着介紹Web端的REPL工具。Repl.it是一個雲端的在線編輯器和IDE,它支持所有主流的編程語言,包括Go。在這個Web端的頁面裏面能夠編輯代碼並執行,Web端也會輸出結果。它支持顯示補全列表和語法高亮,且支持靜態檢查,直接在對應行顯示錯誤緣由。另外能夠生成短鏈接方便分享出去,很是適合快速驗證、教學和演示等用途。

lgo/gophernotes

lgogophernotes都是Golang語言的Jupyter Notebook內核,實現了在Jupyter Notebook(原來的IPython Notebook)上編寫Golang代碼並執行。

Jupyter Notebook是一個交互式筆記本應用,是一個Web應用,算法和數據分析工程師用的比較多。

lgo和gophernotes具體安裝就不演示了,我的以爲仍是在終端REPL更好用。有興趣的能夠看一下gophernotes項目下的動態圖看效果:

代碼地址

原文連接: strconv.com/posts/go-re…

完整代碼能夠在這個地址找到。

相關文章
相關標籤/搜索