以下內容為本人的學習筆記,如需要轉載,請聲明原文鏈接[ 微信公眾號「ENG八戒」](https://mp.weixin.qq.com/s/U6jIT837x5Yxe6Ev1aMDsA)[https://mp.weixin.qq.com/s/U6jIT837x5Yxe6Ev1aMDsA](https: ...
以下內容為本人的學習筆記,如需要轉載,請聲明原文鏈接 微信公眾號「ENG八戒」https://mp.weixin.qq.com/s/U6jIT837x5Yxe6Ev1aMDsA
使用一個簡單的計數程式將古老的 C 語言與現代 Go 進行比較。
Go 是一種現代編程語言,追溯其歷史大部分源自編程語言 C。所以,任何熟悉 C 語言的開發者都可能會覺得 Go 很熟悉。C 程式員使用 Go 編寫新程式變得容易,同時避免了 C 編程語言的許多常見缺陷。
下麵通過實現一個簡單的加法邏輯,來比較 C 和 GO 的區別。該程式將數字從一加到十,計算過程和結果數值都比較小,所以代碼僅使用普通整數變數。像這樣的迴圈邏輯在編程中很常見,所以對比效果會顯而易見。
C 語言做迴圈
C 語言中的基本迴圈是 for 迴圈,它可以實現對一組值的迭代訪問。
for 基本語法:
for (初始化條件; 判斷條件為真; 每次迴圈之後的操作) {
// do something;
}
比如,可以編寫一個迴圈,初始化條件時設置變數 count 為 1,然後判斷 count <= 10 為真時執行 {} 內的語句,在再次執行條件判斷之前,對變數 count 增加 1。直到判斷 count <= 10 為假就退出迴圈。
在每次迭代後,對變數 count 增加 1,除了常規的 count = count + 1 書寫格式之外,也可以對變數採用 ++ 的自加操作符,這種變通可以使得代碼更簡潔易讀。
在迴圈內部,為了直觀查看變數的變化過程,可以使用標準庫函數 printf 列印變數 count 的值:
for (int count = 1; count <= 10; count ++) {
printf("%d\n", count);
}
為了演示完整的邏輯,下麵是一個示常式序,將數字從 1 加到 10,然後列印和的結果。
#include <stdio.h>
int main()
{
puts("adding 1 to 10 ..");
int sum = 0;
for (int count = 1; count <= 10; count ++) {
sum += count;
}
printf("sum is %d\n", sum);
return 0;
}
上面的代碼使用了兩種函數把信息列印出來,最終輸出到標準輸出 stdout。puts 函數列印一個字元串,直到遇到字元串的空字元,而 printf 函數支持格式化列印,非常靈活,所以更常用。關鍵字 %d 表示列印一個十進位(或整數)值,\n 表示換行符。
如果編譯並運行該程式,你將看到以下輸出:
adding 1 to 10 ..
sum is 55
GO 語言做迴圈
在 GO 語言中,同樣提供了 for 迴圈,而且與 C 語言中的 for 迴圈語法非常相似,甚至可以直接轉換成 GO 的書寫格式。
下麵為了直觀查看變數的變化過程,在迴圈內部同樣使用方法列印變數 count 的值:
var count int
for count = 1; count <= 10; count ++ {
fmt.Printf("%d\n", count)
}
fmt 是包名,使用包之前需要先導入,用關鍵詞 import。C 語言中就沒有導入包的概念,只能通過包含頭文件 .h 來引入其它現成模塊。
fmt 實現了類似 C 語言的列印輸出 printf 和讀取輸入 scanf。fmt.Printf 方法也是支持格式化輸出的,甚至格式變數就是從 C 語言的 printf 派生而來。
在 C/C ++ 代碼中,比較推薦的編碼規範中通常每行是只寫一句操作語句,雖然語法上多個操作語句是允許書寫在同一行的,但這樣易讀性就很差。有沒有發現,在每行 GO 語句的末尾都沒有分號 ';' 了? 因為 GO 編譯器預設每行就是一個語句,這樣其實是強制提高了代碼的可讀性。
再來看看 GO 語言實現的完整邏輯,基於上面的 C 語言代碼版本直接翻譯如下
package main
import "fmt"
func main() {
var sum, count int
fmt.Println("adding 1 to 10 ..")
for count = 1; count <= 10; count ++ {
sum = sum + count
}
fmt.Printf("sum is %d\n", sum)
}
上面的代碼是有效和可以正確運行輸出的,但是這很不 GO ! GO 不單單是一門語言,也是一種態度。
有沒有看到 C 語言版本中, for 迴圈里的初始化條件是可以同時聲明定義並賦值變數的?換成在 GO 中是否也支持類似操作?
在 GO 中,有個聲明變數並賦值的操作符 :=,就可以做到
for count := 1; count <= 10; count ++ {
sum = sum + count
}
另外,你如果再細心一點可能會發現,GO 代碼里聲明定義的變數會被預設初始化為 0,而 C 代碼中定義的變數如果未經初始化會是任何未知的值,如此看來 GO 的安全性有了很大的提高。
變數的生命周期管理對開發者來說是很耗費心智的,所以很多時候變數的聲明定義都是應該儘量靠近使用的地方,並且縮窄變數的生命周期,對於事故的發生可以有效縮小排查錯誤的範圍,簡直就是在打救程式員的生命啊。
再來看看,優化後的 GO 範式代碼
package main
import "fmt"
func main() {
fmt.Println("adding 1 to 10 ..")
var sum int
for count := 1; count <= 10; count++ {
sum += count
}
fmt.Printf("sum is %d\n", sum)
}
看到這裡,和 C 代碼的 main 函數比起來,GO 的 main 函數沒有顯式的返回值。實際上,GO 的 main 函數預設返回值 0,如果需要返回其它值,可以調用 os.Exit(n) 返回值 n,這個方法可在任何位置調用,程式會在調用該方法後會終止運行並退出,就類似 C 語言中的標準庫函數 exit(n) 一樣。
簡單回顧
從上面的邏輯實現過程來看,兩種語言實現過程差別不大,語法上是有差別的,書寫的習慣其實就透露著各自的態度。
雖然老氣橫秋的 C 語言代碼很多,但是如果按照現代 C 語言書寫規範來看,GO 的代碼是何其相似。
雖然你會說新出來的語言有很多方便到爆炸的語法糖。但問題是,語言的精髓是語法糖嗎?答案不唯一,酸甜苦辣唯有嘗過的人才知道。