Go語(yǔ)言并不簡(jiǎn)單
Go 不是一種很簡(jiǎn)單的編程語(yǔ)言。盡管它的許多方面都很簡(jiǎn)單:語(yǔ)法很簡(jiǎn)單,大多數(shù)語(yǔ)義也很簡(jiǎn)單。然而,語(yǔ)言不僅僅是語(yǔ)法,我們希望利用它編寫(xiě)出實(shí)用的代碼。利用 Go 編寫(xiě)有用的代碼并不總是那么容易

事實(shí)證明,通過(guò)某種方式將一些簡(jiǎn)單的功能組合在一起,編寫(xiě)出有用的代碼可能會(huì)非常棘手。在 Ruby 中,如何刪除某個(gè)數(shù)組中的一項(xiàng)?list.delete_at(i)。如何通過(guò)值刪除條目?list.delete(value)。非常簡(jiǎn)單!
然而在 Go 中,事情可沒(méi)有那么容易,為了刪除索引 i,你需要執(zhí)行以下操作:

為了刪除值 v,你必須使用循環(huán):

這未免也太復(fù)雜了?也未必,我認(rèn)為即使沒(méi)有 Go 語(yǔ)言經(jīng)驗(yàn),大多數(shù)程序員也可以看懂上述代碼。但它確實(shí)不簡(jiǎn)單。我這個(gè)人比較懶,我會(huì)從 SliceTricks 上復(fù)制這類代碼,因?yàn)槲蚁雽P慕鉀Q實(shí)際問(wèn)題,不想為這類小事苦惱。
此外,Go 語(yǔ)言也很容易出現(xiàn)使用錯(cuò)誤或性能不佳的情況,特別是對(duì)于經(jīng)驗(yàn)不足的程序員而言。例如,我們來(lái)比較一下:將上述復(fù)制到一個(gè)新數(shù)組,和復(fù)制到一個(gè)新的預(yù)分配數(shù)組

盡管在大多數(shù)情況下 1529ns 足夠快了,而且也不必過(guò)分擔(dān)心,但是在許多情況下,性能確實(shí)很重要,而且擁有能保證實(shí)現(xiàn)最佳性能的 list.delete(value)是非常有必要的。
圖片
再舉一個(gè)例子:goroutine?!笆褂?goroutine 并不難,你只需要添加關(guān)鍵字 go,就可以了!”沒(méi)錯(cuò),這樣確實(shí)可以了,但是如果我需要同時(shí)運(yùn)行 500 萬(wàn)個(gè) goroutine 呢?到時(shí)候,你會(huì)納悶,所有內(nèi)存都去哪兒了?而且你很難避免意外“泄漏”goroutine。
有許多模式可以限制 goroutine 的數(shù)量,但哪一種都不簡(jiǎn)單。下面就是一個(gè)簡(jiǎn)單的例子:

我加了一些注釋是有原因的:對(duì)于不熟悉 Go 的人來(lái)說(shuō),這段代碼非常難以理解。上述代碼也不能確保數(shù)字會(huì)按照一定的順序輸出(這可能是一項(xiàng)需求,當(dāng)然也可能不是)。
Go 的并發(fā)原語(yǔ)很簡(jiǎn)單且易于使用,但是將它們組合起來(lái),解決常見(jiàn)的現(xiàn)實(shí)問(wèn)題就沒(méi)有那么簡(jiǎn)單了。
RichHickey 在“Simple Made Easy”中提出,我們不應(yīng)該將“簡(jiǎn)單”與“易于編寫(xiě)”混為一談:即便你只需編寫(xiě)一兩行代碼,也并不意味著底層的概念很簡(jiǎn)單(這里的簡(jiǎn)單指的是淺顯易懂)。
這句話值得人尋味。在大多數(shù)情況下,我們不應(yīng)該為了“易于編寫(xiě)”而犧牲“簡(jiǎn)單”。但這并不意味著我們不應(yīng)該考慮如何讓編程更加簡(jiǎn)單。即便概念很簡(jiǎn)單,也并不意味著易于使用,人們可能會(huì)錯(cuò)誤地使用,或使用的方式會(huì)引發(fā) bug。將 Hickey 的論點(diǎn)推到極致,就會(huì)出現(xiàn) Brainfuck 之類語(yǔ)言,當(dāng)然這很愚蠢。
理想情況下,編程語(yǔ)言應(yīng)該減少推理其行為所需的認(rèn)知負(fù)擔(dān),增加這種認(rèn)知負(fù)擔(dān)的方法有很多:復(fù)雜的語(yǔ)言功能就是其中之一;而人們不得不花費(fèi)精力實(shí)現(xiàn)一些簡(jiǎn)單的概念也是一種負(fù)擔(dān),因?yàn)槲倚枰嗫紤]一段代碼。盡管我不太關(guān)心代碼格式或語(yǔ)法選擇,但我認(rèn)為減少閱讀代碼時(shí)的認(rèn)知負(fù)擔(dān)很重要。
缺少泛型是導(dǎo)致 Go 不那么簡(jiǎn)單的部分原因?,F(xiàn)在很難實(shí)現(xiàn) slices 包之類以通用的方式完成的操作。而泛型可以讓這成為可能,同時(shí)也會(huì)讓編程變得更復(fù)雜(使用了更多的語(yǔ)言功能),但是它們也可以讓編程更加容易,并降低其他方面的復(fù)雜性。
這些是無(wú)法克服的問(wèn)題嗎?不,我仍然會(huì)使用 Go,而且也會(huì)一如既往地喜歡 Go。但是,我不認(rèn)為 Go 是你“可以在 5~10 分鐘之內(nèi)學(xué)會(huì)的語(yǔ)言”。
歸根結(jié)底,學(xué)習(xí)語(yǔ)言不僅僅要學(xué)習(xí)編寫(xiě) if 和 for 的語(yǔ)法,你需要學(xué)習(xí)的是思維方式。我見(jiàn)過(guò)許多 Python 或 C#開(kāi)發(fā)人員嘗試在 Go 語(yǔ)言中實(shí)現(xiàn)那些語(yǔ)言的某些概念或模式。常見(jiàn)的做法包括將結(jié)構(gòu)嵌入作為繼承,將 panics 作為異常,通過(guò) interface{}實(shí)現(xiàn)“偽動(dòng)態(tài)編程”等等。這些做法很難取得良好的結(jié)果。
當(dāng)?shù)谝淮尉帉?xiě) Go 程序時(shí),我也犯了同樣的錯(cuò)誤,這是很自然的事情。在剛接觸 Ruby 的時(shí)候,我曾嘗試用 Ruby 編寫(xiě) Python 代碼(由于這兩種語(yǔ)言很相似,所以結(jié)果相對(duì)好一點(diǎn),但仍然有很多奇怪的做法,比如使用 for 循環(huán))。
這就是為什么我不喜歡人們通過(guò) Go 教程學(xué)習(xí)這門語(yǔ)言的原因,教程只會(huì)講解基本的語(yǔ)法,還有其他的一些知識(shí)。這只能讓你大致感受一下 Go 語(yǔ)言,但并不能幫助你真正學(xué)習(xí)這門語(yǔ)言
文章來(lái)源于網(wǎng)絡(luò),侵刪!
