Emacs給Go一個更好的Playground

題目中雖提到了 Emacs ,但其實本文主要講述是一個Emacs的神級插件---org-mode的故事。 org-mode 不了解的,請自行Google!
在未使用 org-mode 前,學習和實驗Go的特性(例如 context )的步驟如下:

  • 打開終端
  • 跳轉到學習示例目錄下
  • 創建子目錄,例如 context , 然后跳入子目錄, 創建 main.go 文件
  • 編寫簡單的示例代碼
  • 編譯和運行代碼示例,若出錯調試,返回上個步驟

上面的過程有些可精簡,例如在IDE中,目錄跳轉可在對話框中完成,代碼的編寫,編譯和運行都可在IDE中完成。 在IDE中流程如下:

  • 在學習示例目錄下,創建一個新的示例工程
  • 編寫簡單的示例代碼, 編譯和運行

在IDE中,整個流程精簡了很多。 作為語言使用者,我們可能需要把實驗過的示例代碼留存,以便能應用在日后的開發中。 上面的兩個流程,都會根據實驗的包或者語言特性,創建相應的子目錄,經過這樣的處理,代碼示例都聚合到了一起,方便了翻閱和修改。 示例代碼的執行結果,大多是直接輸出到終端的,你要驗證原有示例代碼的執行結果,你必須要重新執行代碼,因為執行結果并沒有留存。 若是這個示例代碼,是很久之前的,可能是一年以前的, 這個時候你看到代碼的時候,可能會時一臉懵逼。 這個時候你會想,為什么當時沒有多留些信息,讓我知道,為什么做這個示例,以及這段代碼完成了什么功能。

Org-mode 簡單配置后, 可完美的解決以上問題,代碼留存,執行結果留存,文學編程(在編碼過程中書寫文檔)。

上圖展示了一個子問題的各個部分,問題描述,解決方案,代碼,以及代碼的執行結果。 子問題對應 Org-mode 中的子目錄,然后所有問題都可聚合在一個 Org-mode 文檔中。 現在流程可簡化為:

  • 跳轉到 Org-mode 文檔中
  • 創建子目錄,書寫解決方案,編碼實現

借助 Org-mode 強大的特性,可很容易的復用代碼以及查詢。

對于 Org-mode 不熟悉的,可先瀏覽Org-mode的主頁。 Org-mode 通過 Babel 執行代碼,對此不熟悉的讀者, 可閱讀我之前翻譯的文檔

ob-go

Babel 可執行多種語言的代碼, 但官方的收錄的語言支持中,沒有Go。 但Go是如此的炙手可熱,沒有官方支持,肯定也會有先行者實現支持。 感謝 popeob-C 實現了ob-go , 實現了 Babel 對于Go的支持。

簡介

ob-go 使 Org-babel 可執行Go代碼。 與解釋語言可直接執行不同,Go需要先編譯為可執行文件,然后運行。 Go代碼通過 go run 命令編譯和運行。 若代碼中沒有 main 函數,默認情況下,代碼會被包裹在簡單的 main 函數中。 若 :package 選項沒設置并且代碼中沒有聲明 package , 則 main package 被聲明。 示例如下,代碼被執行,執行結果被回寫到 buffer 中。

#+BEGIN_SRC go :imports "fmt"
  fmt.Println("Hello, org-mode")
#+END_SRC

#+RESULTS:
: Hello, org-mode

使用快捷鍵 C-c C-v v 可查看被擴展后的代碼。

Go特定的頭參數(Header Arguments)

除了 Babel 的常規頭參數之外,下面是一些Go語言特定的頭文件。

  • :args: 傳遞命令行參數到代碼編譯后的可執行文件,傳遞超過多參數,需要使用 list 。
  • :flags: 傳遞給 go run 或者 go build 的flags(未使用成功)。
  • :main: 若沒設置 no , 代碼將會被包裹在 main 函數中。默認 yes
  • :imports: 為代碼提供 imports 的快捷支持。 當處理 main 函數時,應該使用這個選項。 要 import 多個包,請使用 list
  • :package: 設置當前代碼塊 tangle 時的包名。 需要: :main no 。 若沒設置,同時代碼中沒有包名聲明, main 包將被聲明。
  • :var: ob-go 支持 Babel 的變量,不過目前還不完備。

配置

這里假設Go的開發環境已經配置完畢,同時你的機器上的 EmacsOrg-mode 都是最近的版本,對于 Babel 都是完整支持的。 由于 ob-go 沒有并入 Org-mode 所以需要單獨配置。 步驟如下:

  • M-x find-library ob-C , 找到的目錄 org-plus-contrib

  • 新建 ob-go.el , 然后把 github中代碼 復制到新建的文件中

  • 配置 org-babel-load-languages, 如下:

    (org-babel-do-load-languages
     'org-babel-load-languages
     '((python . t)
       (C . t)
       (go . t)
       (emacs-lisp . t)
       (shell . t)))
    

編碼流程

最近在 LeetCode 上做編程訓練,這里就以解決上面的問題的流程來做說明。

  • 在LeetCode頁面上,仔細閱讀和理解問題,這里以 Merge Two Binary Trees 為例

  • 跳轉到 leetcode.org , 創建 merge two binary trees 子目錄

  • 創建名為 merge-two-bt 的Go代碼塊

  • 通過快捷鍵 C-c ' 打開Go語言特定的編輯模式buffer中,然后編碼。 在編碼過程完成后, C-c ' 完成并關閉編輯buffer;或者對自己編輯不滿意, C-c C-k 取消編輯并關閉編輯buffer。

  • 把定義好的代碼塊整合到一起,然后執行(完整代碼)。

使用示例

導入多個包

#+BEGIN_SRC go :imports '("fmt" "time")
  fmt.Println("當前時間:", time.Now())
#+END_SRC

#+RESULTS:
: 當前時間: 2017-06-12 18:04:20.562355811 +0800 CST

命令行參數傳遞

#+BEGIN_SRC go :imports '("fmt" "os") :args '("bable" "golang")
  fmt.Println(os.Args[1], os.Args[2])
#+END_SRC

#+RESULTS:
: bable golang

多入參

#+NAME: sum
#+BEGIN_SRC go :imports "fmt" :var a=12 b=13
  fmt.Println(a+b)
#+END_SRC

#+RESULTS:
: 25

#+call: sum(a=22,b=23)

#+RESULTS:
: 45

代碼組織

#+NAME: min
#+BEGIN_SRC  go
  func min(a, b int) int {
    if a > b {
      return b
    } else {
      return a
    }
  }
#+END_SRC

#+NAME: get-min
#+BEGIN_SRC go :var a=0 b=0 :imports "fmt" :noweb strip-export
  <<min>>

  func main() {
    fmt.Println(min(a,b))
  }
#+END_SRC

#+call: get-min(27, 23)

#+RESULTS:
: 23

總結

Org-mode于我來說,就是一個神器,打破了我對一個編輯器的認知,打破了我對一個信息收集器的認知。 Org-mode依托于強大的 Emacs, 借助于 Babel, 使文檔和代碼無縫的結合在了一起, 一會編碼,一會記錄, 一會調試,一會執行。 不失為,學習語言,嘗試新工具的不二神器。 再來一段Go代碼:

#+BEGIN_SRC go :imports "fmt"
  fmt.Println("Goodbye, Gopher!")
#+END_SRC
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 序言 概述 初始配置 代碼塊代碼塊在 Org-mode 中代碼塊在 Babel 中 源代碼執行示例RubyShel...
    brantou閱讀 4,081評論 0 7
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,837評論 18 139
  • Spring Boot 參考指南 介紹 轉載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,925評論 6 342
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,841評論 25 708
  • 這是爸媽在我家住的最后一個晚上,明天他們就要回他們的家了,在兩千公里外的長春,有一個七十多平米的老樓房,那曾...
    莫聽穿林閱讀 1,087評論 7 5