開放出版:圖靈機——樊虹劍《Go語言·雲動力》樣章
本樣章為未經編輯的作者原稿。
作者自述
樊虹劍。15歲迷上Apple II。立志成為程式設計師。從Applesoft BASIC,到Microsoft C、C++、C#,又到Apple Objective-C,其間使用過大小十幾種程式語言,始終不得要領。不明白髮源於數學和電子學的電腦科學,為何不去追求詩歌般至簡至純的美學,而是纏繞於繁複的形式和糾結於空洞的哲學。幾欲放棄。直到偶然發現Plan 9,才知道返璞歸真的樂趣,並一路歡喜走過Inferno,快樂走入Go語言的世界。
圖靈機
Go作為高階語言,當然是圖靈完備的。我們用Go來寫一個最簡單的圖靈機,使用腦操程式語言,下面的程式可以輸出“hi”:
++++++++++[>++++++++++<-]>++++.+.
此程式語言僅有7條指令,理論上和任何圖靈完備的語言等價。但程式設計師使用什麼語言的表達能力和效率,是有云泥之分的。這也是為什麼人們總是在探索新的語言,提高表達效率。
這7條指令是:
+ 使當前資料單元的值增一
- 使當前資料單元的值減一
> 下一個單元作為當前資料單元
< 上一個單元作為當前資料單元
[ 如果當前資料單元的值為0, 下一指令在對應的]後
] 如果當前資料單元的值不為0, 下一指令在對應的[後
. 把當前資料單元的值作為字元輸出
這樣,當前單元的值加10,作為[和]的迴圈變數,>到下一單元,也加10,<-使迴圈變數減一,迴圈10遍,再加4,得到104,是字元h的UTF8編碼,輸出,再加1,輸出i。
package main
import "fmt"
var (
a [30000]byte
prog = "++++++++++[>++++++++++<-]>++++.+."
p, pc int
)
func loop(inc int) {
for i := inc; i != 0; pc += inc {
switch prog[pc+inc] {
case '[':
i++
case ']':
i--
}
}
}
func main() {
for {
switch prog[pc] {
case '>':
p++
case '<':
p--
case '+':
a[p]++
case '-':
a[p]--
case '.':
fmt.Print(string(a[p]))
case '[':
if a[p] == 0 {
loop(1)
}
case ']':
if a[p] != 0 {
loop(-1)
}
default:
fmt.Println("Illegal instruction")
}
pc++
if pc == len(prog) {
return
}
}
}
程式一開始的變數a是我們圖靈機的資料記憶體,prog是指令記憶體,p和pc分別是這兩個記憶體的指標,代表當前資料單元和當前指令。
函式loop執行[和]指令,移動指令指標pc。這裡用到了三段式的for語句,也就是:
for 初始;判斷;增值 {
初始在迴圈開始前執行一次,通常是給迴圈控制變數一個初始值,然後每次判斷如果真,就執行大括號的語句塊一次,再執行增值的部分,再判斷、執行、增值,直到判斷為假,才跳過大括號的塊,繼續其後的語句。
switch是Go的單項選擇語句。它根據後面的值,選擇執行大括號裡的某一個case分支。同樣的for和switch語句,也出現在main函式裡。但那裡的for,沒有三段式,所以會一直迴圈,直到return結束。而那裡的switch,有一個default分支,當其它的case都不是switch的值時,選擇執行default分支。
此程式還用到了++和--語句,給變數加一和減一。例如p++就是p = p + 1,也可以寫為p += 1。這裡,函式loop的for語句的第三段增值部分的pc += inc,就是pc = pc + inc的縮寫。
注意++和--是單獨的語句,不是表示式,不可以用在其它語句裡。象*p++=*q++這種高明的C語句,在Go裡是不能用的。目的是避免語義誤導,給程式設計師少一點犯錯的機會。
而這種加減一的操作,主要用來移動陣列的下標。例如,p和pc分別是陣列a和prog的下標,這樣a[p]和prog[pc]就分別是對應下標的陣列的單元的值。
至此,我們應該可以理解此程式了。作為練習,請讀者拿出紙筆,畫一條33個格子的帶子,逐一填上prog的每個字元,這就是prog陣列,也是圖靈機的指令記憶體。再畫一條至少兩個格子的帶子,作為陣列a,也就是圖靈機的資料記憶體,然後,執行每一條指令,看資料格子是怎樣更新的。我們明白了圖靈機器,也就明白了計算機器的理論基礎。
在某些人看來,物理的宇宙也是如此執行的。一切皆是宿命、神旨、歷史規律。但還有人認為,在這個無限的宇宙裡,沒有不可能,再小的機率也一定會發生,一切都不是確定的,所以機械的圖靈機理論不適用。更何況,作為物理宇宙的取樣觀察者,人類太渺小,取樣太少,是不可能正確解讀物理宇宙的資訊的。人,還是應該先觀察明白自己身邊的小事情,看怎樣寫的指令才能體現自己和人類整體的價值,而自己又是不是改變資料的那條指令?
好了,哲學人生觀的討論對Go的程式設計毫無幫助,我們還是檢討一下都學會了哪些Go的語法:包、函式、變數、常量、賦值、型別、字串、陣列、表示式、比較邏輯算數操作符、if、else、for、switch、case、++和--。夠用了。下面我們不再用無用的例子,而是直接給出幾個完整的工具程式。
相關文章
- 開放出版:許式偉《Go語言程式設計》樣章“物件導向程式設計”Go程式設計物件
- 未來的圖靈出版是怎樣的?圖靈
- 怎樣給圖靈出版的圖書提交勘誤圖靈
- 動態語言的靈活性是把雙刃劍 -- 以 Python 語言為例Python
- 圖靈公司敏捷出版實踐圖靈敏捷
- 許式偉《Go語言程式設計》章節摘錄:Go語言簡史Go程式設計
- 開放出版:為什麼我們需要一門新語言?許式偉《Go語言程式設計》序Go程式設計
- Go 語言學習腦圖Go
- Go語言入門經典第18章Go
- go語言安卓開發Go安卓
- go與其他語言有什麼區別?學習go語言怎麼樣Go
- Go語言Interface機制解析Go
- 第09章 Go語言併發,Golang併發Golang
- Go語言————1、初識GO語言Go
- 【Go語言繪圖】圖片新增文字(二)Go繪圖
- 【Go語言繪圖】圖片的旋轉Go繪圖
- 【Go語言繪圖】圖片新增文字(一)Go繪圖
- go語言程式設計前景怎麼樣?國內Go語言佈道師許式偉這樣說Go程式設計
- 今天收到圖靈出版的兩本書圖靈
- Go是一門什麼樣的語言?Go
- 《快學 Go 語言》第 5 課 —— 靈活的切片Go
- 最新Go語言學習路線圖 帶你通關Go語言-千鋒Go
- 新書《Go 語言程式設計之旅:一起用 Go 做專案》出版啦!新書Go程式設計
- GO語言Go
- 圖解Go語言記憶體分配圖解Go記憶體
- Go語言面試題分享:選擇題11道(2)go語言開發Go面試題
- 使用go語言開發自動化API測試工具GoAPI
- GO語言————2、GO語言環境安裝Go
- 《Go語言高階程式設計》開源免費圖書Go程式設計
- Go語言的context包從放棄到入門GoContext
- GO 語言快速開發入門Go
- 如何開始學習Go語言Go
- go語言開發有哪些工具Go
- Go語言開發環境搭建Go開發環境
- 開心檔之Go 語言常量Go
- Go語言錯誤處理機制Go
- 有Go語言實戰培訓班嗎?go語言開發環境搭建Go開發環境
- 《Go 語言併發之道》讀後感 - 第二章Go