題目中雖提到了 Emacs
,但其實(shí)本文主要講述是一個(gè)Emacs
的神級(jí)插件---org-mode
的故事贴膘。 org-mode
不了解的姆怪,請(qǐng)自行Google!
在未使用 org-mode
前誊役,學(xué)習(xí)和實(shí)驗(yàn)Go的特性(例如 context )的步驟如下:
- 打開(kāi)終端
- 跳轉(zhuǎn)到學(xué)習(xí)示例目錄下
- 創(chuàng)建子目錄贞奋,例如 context , 然后跳入子目錄, 創(chuàng)建 main.go 文件
- 編寫(xiě)簡(jiǎn)單的示例代碼
- 編譯和運(yùn)行代碼示例,若出錯(cuò)調(diào)試,返回上個(gè)步驟
上面的過(guò)程有些可精簡(jiǎn),例如在IDE中虚汛,目錄跳轉(zhuǎn)可在對(duì)話(huà)框中完成,代碼的編寫(xiě)皇帮,編譯和運(yùn)行都可在IDE中完成。 在IDE中流程如下:
- 在學(xué)習(xí)示例目錄下蛋辈,創(chuàng)建一個(gè)新的示例工程
- 編寫(xiě)簡(jiǎn)單的示例代碼, 編譯和運(yùn)行
在IDE中属拾,整個(gè)流程精簡(jiǎn)了很多将谊。 作為語(yǔ)言使用者,我們可能需要把實(shí)驗(yàn)過(guò)的示例代碼留存渐白,以便能應(yīng)用在日后的開(kāi)發(fā)中尊浓。 上面的兩個(gè)流程,都會(huì)根據(jù)實(shí)驗(yàn)的包或者語(yǔ)言特性纯衍,創(chuàng)建相應(yīng)的子目錄栋齿,經(jīng)過(guò)這樣的處理,代碼示例都聚合到了一起襟诸,方便了翻閱和修改瓦堵。 示例代碼的執(zhí)行結(jié)果,大多是直接輸出到終端的歌亲,你要驗(yàn)證原有示例代碼的執(zhí)行結(jié)果菇用,你必須要重新執(zhí)行代碼,因?yàn)閳?zhí)行結(jié)果并沒(méi)有留存陷揪。 若是這個(gè)示例代碼惋鸥,是很久之前的,可能是一年以前的悍缠, 這個(gè)時(shí)候你看到代碼的時(shí)候卦绣,可能會(huì)時(shí)一臉懵逼。 這個(gè)時(shí)候你會(huì)想飞蚓,為什么當(dāng)時(shí)沒(méi)有多留些信息滤港,讓我知道,為什么做這個(gè)示例玷坠,以及這段代碼完成了什么功能蜗搔。
Org-mode
簡(jiǎn)單配置后, 可完美的解決以上問(wèn)題八堡,代碼留存樟凄,執(zhí)行結(jié)果留存,文學(xué)編程(在編碼過(guò)程中書(shū)寫(xiě)文檔)兄渺。
上圖展示了一個(gè)子問(wèn)題的各個(gè)部分缝龄,問(wèn)題描述,解決方案挂谍,代碼叔壤,以及代碼的執(zhí)行結(jié)果。 子問(wèn)題對(duì)應(yīng) Org-mode
中的子目錄口叙,然后所有問(wèn)題都可聚合在一個(gè) Org-mode
文檔中炼绘。 現(xiàn)在流程可簡(jiǎn)化為:
- 跳轉(zhuǎn)到
Org-mode
文檔中 - 創(chuàng)建子目錄,書(shū)寫(xiě)解決方案妄田,編碼實(shí)現(xiàn)
借助 Org-mode
強(qiáng)大的特性俺亮,可很容易的復(fù)用代碼以及查詢(xún)驮捍。
對(duì)于 Org-mode
不熟悉的,可先瀏覽Org-mode的主頁(yè)脚曾。 Org-mode
通過(guò) Babel
執(zhí)行代碼东且,對(duì)此不熟悉的讀者, 可閱讀我之前翻譯的文檔本讥。
ob-go
Babel
可執(zhí)行多種語(yǔ)言的代碼珊泳, 但官方的收錄的語(yǔ)言支持中,沒(méi)有Go拷沸。 但Go是如此的炙手可熱色查,沒(méi)有官方支持,肯定也會(huì)有先行者實(shí)現(xiàn)支持堵漱。 感謝 pope 在 ob-C 實(shí)現(xiàn)了ob-go , 實(shí)現(xiàn)了 Babel
對(duì)于Go的支持综慎。
簡(jiǎn)介
ob-go 使 Org-babel 可執(zhí)行Go代碼。 與解釋語(yǔ)言可直接執(zhí)行不同勤庐,Go需要先編譯為可執(zhí)行文件示惊,然后運(yùn)行。 Go代碼通過(guò) go run
命令編譯和運(yùn)行愉镰。 若代碼中沒(méi)有 main
函數(shù)米罚,默認(rèn)情況下,代碼會(huì)被包裹在簡(jiǎn)單的 main
函數(shù)中丈探。 若 :package
選項(xiàng)沒(méi)設(shè)置并且代碼中沒(méi)有聲明 package
录择, 則 main
package 被聲明。 示例如下碗降,代碼被執(zhí)行隘竭,執(zhí)行結(jié)果被回寫(xiě)到 buffer
中。
#+BEGIN_SRC go :imports "fmt"
fmt.Println("Hello, org-mode")
#+END_SRC
#+RESULTS:
: Hello, org-mode
使用快捷鍵 C-c C-v v
可查看被擴(kuò)展后的代碼讼渊。
Go特定的頭參數(shù)(Header Arguments)
除了 Babel
的常規(guī)頭參數(shù)之外动看,下面是一些Go語(yǔ)言特定的頭文件。
-
:args
: 傳遞命令行參數(shù)到代碼編譯后的可執(zhí)行文件爪幻,傳遞超過(guò)多參數(shù)菱皆,需要使用list
。 -
:flags
: 傳遞給go run
或者go build
的flags(未使用成功)挨稿。 -
:main
: 若沒(méi)設(shè)置no
仇轻, 代碼將會(huì)被包裹在main
函數(shù)中。默認(rèn)yes
奶甘。 -
:imports
: 為代碼提供 imports 的快捷支持篷店。 當(dāng)處理main
函數(shù)時(shí),應(yīng)該使用這個(gè)選項(xiàng)臭家。 要 import 多個(gè)包船庇,請(qǐng)使用list
吭产。 -
:package
: 設(shè)置當(dāng)前代碼塊 tangle 時(shí)的包名侣监。 需要::main no
鸭轮。 若沒(méi)設(shè)置,同時(shí)代碼中沒(méi)有包名聲明橄霉,main
包將被聲明窃爷。 -
:var
:ob-go
支持Babel
的變量,不過(guò)目前還不完備姓蜂。
配置
這里假設(shè)Go的開(kāi)發(fā)環(huán)境已經(jīng)配置完畢按厘,同時(shí)你的機(jī)器上的 Emacs
和 Org-mode
都是最近的版本,對(duì)于 Babel
都是完整支持的钱慢。 由于 ob-go
沒(méi)有并入 Org-mode
所以需要單獨(dú)配置逮京。 步驟如下:
M-x find-library ob-C
, 找到的目錄org-plus-contrib
新建 ob-go.el , 然后把 github中代碼 復(fù)制到新建的文件中
-
配置
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 上做編程訓(xùn)練,這里就以解決上面的問(wèn)題的流程來(lái)做說(shuō)明束莫。
在LeetCode頁(yè)面上懒棉,仔細(xì)閱讀和理解問(wèn)題,這里以 Merge Two Binary Trees 為例
跳轉(zhuǎn)到 leetcode.org 览绿, 創(chuàng)建 merge two binary trees 子目錄
創(chuàng)建名為 merge-two-bt 的Go代碼塊
-
通過(guò)快捷鍵
C-c '
打開(kāi)Go語(yǔ)言特定的編輯模式buffer中,然后編碼策严。 在編碼過(guò)程完成后,C-c '
完成并關(guān)閉編輯buffer饿敲;或者對(duì)自己編輯不滿(mǎn)意妻导,C-c C-k
取消編輯并關(guān)閉編輯buffer。 -
把定義好的代碼塊整合到一起怀各,然后執(zhí)行(完整代碼)倔韭。
使用示例
導(dǎo)入多個(gè)包
#+BEGIN_SRC go :imports '("fmt" "time")
fmt.Println("當(dāng)前時(shí)間:", time.Now())
#+END_SRC
#+RESULTS:
: 當(dāng)前時(shí)間: 2017-06-12 18:04:20.562355811 +0800 CST
命令行參數(shù)傳遞
#+BEGIN_SRC go :imports '("fmt" "os") :args '("bable" "golang")
fmt.Println(os.Args[1], os.Args[2])
#+END_SRC
#+RESULTS:
: bable golang
多入?yún)?/h2>
#+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
總結(jié)
#+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于我來(lái)說(shuō),就是一個(gè)神器瓢对,打破了我對(duì)一個(gè)編輯器的認(rèn)知寿酌,打破了我對(duì)一個(gè)信息收集器的認(rèn)知。 Org-mode依托于強(qiáng)大的 Emacs, 借助于 Babel, 使文檔和代碼無(wú)縫的結(jié)合在了一起, 一會(huì)編碼沥曹,一會(huì)記錄份名, 一會(huì)調(diào)試,一會(huì)執(zhí)行妓美。 不失為僵腺,學(xué)習(xí)語(yǔ)言,嘗試新工具的不二神器壶栋。 再來(lái)一段Go代碼:
#+BEGIN_SRC go :imports "fmt"
fmt.Println("Goodbye, Gopher!")
#+END_SRC