rune是Go語(yǔ)言中一種特殊的數(shù)據(jù)類型,它是int32的別名,幾乎在所有方面等同于int32,用于區(qū)分字符值和整數(shù)值,官方解釋如下:
網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)!專注于網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、小程序開發(fā)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了房縣免費(fèi)建站歡迎大家使用!
下面我們通過(guò)一個(gè)例子來(lái)看一下:
我們猜測(cè)一下結(jié)果,hello5 個(gè)字符+1 個(gè)空格+3 個(gè)漢子,算起來(lái)應(yīng)該是 9 個(gè),長(zhǎng)度為 9 才對(duì),但是我們執(zhí)行一下,
結(jié)果打印是 15,這是為什么呢?
所以計(jì)算出的長(zhǎng)度就等于 5+1+3*3=15
如果我們需要計(jì)算出字符串的長(zhǎng)度,而不是底層字節(jié)的個(gè)數(shù),那么可以使用下面的方法:
運(yùn)行結(jié)果如下:
在 rune 定義上方還有一個(gè),byte = uint8
作者:andruzhang,騰訊 IEG 后臺(tái)開發(fā)工程師
在后臺(tái)開發(fā)中,針對(duì)錯(cuò)誤處理,有三個(gè)維度的問題需要解決:
一個(gè)面向過(guò)程的函數(shù),在不同的處理過(guò)程中需要 handle 不同的錯(cuò)誤信息;一個(gè)面向?qū)ο蟮暮瘮?shù),針對(duì)一個(gè)操作所返回的不同類型的錯(cuò)誤,有可能需要進(jìn)行不同的處理。此外,在遇到錯(cuò)誤時(shí),也可以使用斷言的方式,快速中止函數(shù)流程,大大提高代碼的可讀性。
在許多高級(jí)語(yǔ)言中都提供了 try ... catch 的語(yǔ)法,函數(shù)內(nèi)部可以通過(guò)這種方案,實(shí)現(xiàn)一個(gè)統(tǒng)一的錯(cuò)誤處理邏輯。而即便是 C 這種 “中級(jí)語(yǔ)言” 雖然沒有,但是程序員也可以使用宏定義的方式,來(lái)實(shí)現(xiàn)某種程度上的錯(cuò)誤斷言。
但是,對(duì)于 Go 的情況就比較尷尬了。
我們先來(lái)看斷言,我們的目的是,僅使用一行代碼就能夠檢查錯(cuò)誤并終止當(dāng)前函數(shù)。由于沒有 throw,沒有宏,如果要實(shí)現(xiàn)一行斷言,有兩種方法。
第一種是把 if 的錯(cuò)誤判斷寫在一行內(nèi),比如:
第二種方法是借用 panic 函數(shù),結(jié)合 recover 來(lái)實(shí)現(xiàn):
這兩種方法都值得商榷。
首先,將 if 寫在同一行內(nèi)的問題有:
至于第二種方法,我們要分情況看;
不過(guò)使用 panic 來(lái)斷言的方案,雖然在業(yè)務(wù)邏輯中基本上不用,但在測(cè)試場(chǎng)景下則是非常常見的。測(cè)試嘛,用牛刀有何不可?稍微大一點(diǎn)的系統(tǒng)開銷也沒啥問題。對(duì)于 Go 來(lái)說(shuō),非常熱門的單元測(cè)試框架 goconvey 就是使用 panic 機(jī)制來(lái)實(shí)現(xiàn)單元測(cè)試中的斷言,用的人都說(shuō)好。
綜上,在 Go 中,對(duì)于業(yè)務(wù)代碼,筆者不建議采用斷言,遇到錯(cuò)誤的時(shí)候建議還是老老實(shí)實(shí)采用這種格式:
而在單測(cè)代碼中,則完全可以大大方方地采用類似于 goconvey 之類基于 panic 機(jī)制的斷言。
眾所周知 Go 是沒有 try ... catch 的,而且從官方的態(tài)度來(lái)看,短時(shí)間內(nèi)也沒有考慮的計(jì)劃。但程序員有這個(gè)需求呀。筆者采用的方法,是將需要返回的 err 變量在函數(shù)內(nèi)部全局化,然后結(jié)合 defer 統(tǒng)一處理:
這種方案要特別注意變量作用域問題.比如前面的 if err = DoSomething(); err != nil { 行,如果我們將 err = ... 改為 err := ...,那么這一行中的 err 變量和函數(shù)最前面定義的 (err error) 不是同一個(gè)變量,因此即便在此處發(fā)生了錯(cuò)誤,但是在 defer 函數(shù)中無(wú)法捕獲到 err 變量了。
在 try ... catch 方面,筆者其實(shí)沒有特別好的方法來(lái)模擬,即便是上面的方法也有一個(gè)很讓人頭疼的問題:defer 寫法導(dǎo)致錯(cuò)誤處理前置,而正常邏輯后置了,從可讀性的角度來(lái)說(shuō)非常不友好。因此也希望讀者能夠指教。同時(shí)還是希望 Go 官方能夠繼續(xù)迭代,支持這種語(yǔ)法。
這一點(diǎn)在 Go 里面,一開始看起來(lái)還是比較統(tǒng)一的,這就是 Go 最開始就定義的 error 類型,以系統(tǒng)標(biāo)準(zhǔn)的方式,統(tǒng)一了進(jìn)程內(nèi)函數(shù)級(jí)的錯(cuò)誤返回模式。調(diào)用方使用 if err != nil 的統(tǒng)一模式,來(lái)判斷一個(gè)調(diào)用是不是成功了。
但是隨著 Go 的逐步推廣,由于 error 接口的高自由度,程序員們對(duì)于 “如何判斷該錯(cuò)誤是什么錯(cuò)誤” 的時(shí)候,出現(xiàn)了分歧。
在 Go 1.13 之前,對(duì)于 error 類型的傳遞,有三種常見的模式:
這個(gè)流派很簡(jiǎn)單,就是將各種錯(cuò)誤信息直接定義為一個(gè)類枚舉值的模式,比如:
當(dāng)遇到相應(yīng)的錯(cuò)誤信息時(shí),直接返回對(duì)應(yīng)的 error 類枚舉值就行了。對(duì)于調(diào)用方也非常方便,可以采用 switch - case 來(lái)判斷錯(cuò)誤類型:
個(gè)人覺得這種設(shè)計(jì)模式本質(zhì)上還是 C error code 模式。
這種流派則是充分使用了 “error 是一個(gè) interface” 的特性,重新自定義一個(gè) error 類型。一方面是用不同的類型來(lái)表示不同的錯(cuò)誤分類,另一方面則能夠?qū)崿F(xiàn)對(duì)于同一錯(cuò)誤類型,能夠給調(diào)用方提供更佳詳盡的信息。舉個(gè)例子,我們可以定義多個(gè)不同的錯(cuò)誤類型如下:
對(duì)于調(diào)用方,則通過(guò)以下代碼來(lái)判斷不同的錯(cuò)誤:
這種模式,一方面可以透?jìng)鞯讓渝e(cuò)誤,另一方面又可以添加自定義的信息。但對(duì)于調(diào)用方而言,災(zāi)難在于如果要判斷某一個(gè)錯(cuò)誤的具體類型,只能用 strings.Contains() 來(lái)實(shí)現(xiàn),而錯(cuò)誤的具體描述文字是不可靠的,同一類型的信息可能會(huì)有不同的表達(dá);而在 fmt.Errorf 的過(guò)程中,各個(gè)業(yè)務(wù)添加的額外信息也可能會(huì)有不同的文字,這帶來(lái)了極大的不可靠性,提高了模塊之間的耦合度。
在 go 1.13 版本發(fā)布之后,針對(duì) fmt.Errorf 增加了 wraping 功能,并在 errors 包中添加了 Is() 和 As() 函數(shù)。關(guān)于這個(gè)模式的原理和使用已經(jīng)有很多文章了,本文就不再贅述。
這個(gè)功能,合并并改造了前文的所謂 “== 流派” 和 “fmt.Errorf” 流派,統(tǒng)一使用 errors.Is() 函數(shù);此外,也算是官方對(duì)類型斷言流派的認(rèn)可(專門用 As() 函數(shù)來(lái)支持)。
在實(shí)際應(yīng)用中,函數(shù)/模塊透?jìng)麇e(cuò)誤時(shí),應(yīng)該采用 Go 的 error wrapping 模式,也就是 fmt.Errorf() 配合 %w 使用,業(yè)務(wù)方可以放心地添加自己的錯(cuò)誤信息,只要調(diào)用方統(tǒng)一采用 errors.Is() 和 errors.As() 即可。
服務(wù)/系統(tǒng)層面的錯(cuò)誤信息返回,大部分協(xié)議都可以看成是 code - message 模式或者是其變體:
這種模式的特點(diǎn)是:code 是給程序代碼使用的,代碼判斷這是一個(gè)什么類型的錯(cuò)誤,進(jìn)入相應(yīng)的分支處理;而 message 是給人看的,程序可以以某種形式拋出或者記錄這個(gè)錯(cuò)誤信息,供用戶查看。
在這一層面有什么問題呢?code for computer,message for user,好像挺好的。
但有時(shí)候,我們可能會(huì)收到用戶/客戶反饋一個(gè)問題:“XXX 報(bào)錯(cuò)了,幫忙看看什么問題?”。用戶看不懂我們的錯(cuò)誤提示嗎?
在筆者的經(jīng)驗(yàn)中,我們?cè)谑褂?code - message 機(jī)制的時(shí)候,特別是業(yè)務(wù)初期,難以避免的是前后端的設(shè)計(jì)文案沒能完整地覆蓋所有的錯(cuò)誤用例,或者是錯(cuò)誤極其罕見。因此當(dāng)出現(xiàn)錯(cuò)誤時(shí),提示曖昧不清(甚至是直接提示錯(cuò)誤信息),導(dǎo)致用戶從錯(cuò)誤信息中找到解決方案
在這種情況下,盡量覆蓋所有錯(cuò)誤路徑肯定是最完美的方法。不過(guò)在做到這一點(diǎn)之前,碼農(nóng)們往往有下面的解決方案:
既要隱藏信息,又要暴露信息,我可以摔盤子嗎……
這里,筆者從日益普及的短信驗(yàn)證碼有了個(gè)靈感——人的短期記憶對(duì) 4 個(gè)字符還是比較強(qiáng)的,因此我們可以考慮把錯(cuò)誤代碼縮短到 4 個(gè)字符——不區(qū)分大小寫,因?yàn)槿绻嗽谟洃洉r(shí)還要記錄大小寫的話,難度會(huì)增加不少。
怎么用 4 個(gè)字符表示盡量多的數(shù)據(jù)呢?數(shù)字+字母總共有 36 個(gè)字符,理論上使用 4 位 36 進(jìn)制可以表示 36x36x36x36 = 1679616 個(gè)值。因此我們只要找到一個(gè)針對(duì)錯(cuò)誤信息字符串的哈希算法,把輸出值限制在 1679616 范圍內(nèi)就行了。
這里我采用的是 MD5 作為例子。MD5 的輸出是 128 位,理論上我可以取 MD5 的輸出,模 1679616 就可以得到一個(gè)簡(jiǎn)易的結(jié)果。實(shí)際上為了減少除法運(yùn)算,我采用的是取高 20 位(0xFFFFF)的簡(jiǎn)易方式(20 位二進(jìn)制的最大值為 1048575),然后將這個(gè)數(shù)字轉(zhuǎn)成 36 進(jìn)制的字符串輸出。
當(dāng)出現(xiàn)異常錯(cuò)誤時(shí),我們可以將 message 的提示信息如下展示:“未知錯(cuò)誤,錯(cuò)誤代碼 30EV,如需協(xié)助,請(qǐng)聯(lián)系 XXX”。順帶一提,30EV 是 "Access denied for user 'db_user'@'127.0.0.1'" 的計(jì)算結(jié)果,這樣一來(lái),我就對(duì)調(diào)用方隱藏了敏感信息。
至于后臺(tái)側(cè),還是需要實(shí)實(shí)在在地將這個(gè)哈希值和具體的錯(cuò)誤信息記錄在日志或者其他支持搜索的渠道里。當(dāng)用戶提供該代碼時(shí),可以快速定位。
這種方案的優(yōu)點(diǎn)很明顯:
簡(jiǎn)易的錯(cuò)誤碼生成代碼如下:
當(dāng)然這種方案也有局限性,筆者能想到的是需要注意以下兩點(diǎn):
此外,筆者需要再?gòu)?qiáng)調(diào)的是:在開發(fā)中,針對(duì)各種不同的、正式的錯(cuò)誤用例依然需要完整覆蓋,盡可能通過(guò)已有的 code - message 機(jī)制將足夠清晰的信息告知主調(diào)方。這種 hashcode 的錯(cuò)誤代碼生成方法,僅適用于錯(cuò)誤用例遺漏、或者是快速迭代過(guò)程中,用于發(fā)現(xiàn)和調(diào)試遺漏的錯(cuò)誤用例的臨時(shí)方案。
本教程介紹了 Go 中模糊測(cè)試的基礎(chǔ)知識(shí)。通過(guò)模糊測(cè)試,隨機(jī)數(shù)據(jù)會(huì)針對(duì)您的測(cè)試運(yùn)行,以嘗試找出漏洞或?qū)е卤罎⒌妮斎???梢酝ㄟ^(guò)模糊測(cè)試發(fā)現(xiàn)的一些漏洞示例包括 SQL 注入、緩沖區(qū)溢出、拒絕服務(wù)和跨站點(diǎn)腳本攻擊。
在本教程中,您將為一個(gè)簡(jiǎn)單的函數(shù)編寫一個(gè)模糊測(cè)試,運(yùn)行 go 命令,并調(diào)試和修復(fù)代碼中的問題。
首先,為您要編寫的代碼創(chuàng)建一個(gè)文件夾。
1、打開命令提示符并切換到您的主目錄。
在 Linux 或 Mac 上:
在 Windows 上:
2、在命令提示符下,為您的代碼創(chuàng)建一個(gè)名為 fuzz 的目錄。
3、創(chuàng)建一個(gè)模塊來(lái)保存您的代碼。
運(yùn)行g(shù)o mod init命令,為其提供新代碼的模塊路徑。
接下來(lái),您將添加一些簡(jiǎn)單的代碼來(lái)反轉(zhuǎn)字符串,稍后我們將對(duì)其進(jìn)行模糊測(cè)試。
在此步驟中,您將添加一個(gè)函數(shù)來(lái)反轉(zhuǎn)字符串。
a.使用您的文本編輯器,在 fuzz 目錄中創(chuàng)建一個(gè)名為 main.go 的文件。
獨(dú)立程序(與庫(kù)相反)始終位于 package 中main。
此函數(shù)將接受string,使用byte進(jìn)行循環(huán) ,并在最后返回反轉(zhuǎn)的字符串。
此函數(shù)將運(yùn)行一些Reverse操作,然后將輸出打印到命令行。這有助于查看運(yùn)行中的代碼,并可能有助于調(diào)試。
e.該main函數(shù)使用 fmt 包,因此您需要導(dǎo)入它。
第一行代碼應(yīng)如下所示:
從包含 main.go 的目錄中的命令行,運(yùn)行代碼。
可以看到原來(lái)的字符串,反轉(zhuǎn)它的結(jié)果,然后再反轉(zhuǎn)它的結(jié)果,就相當(dāng)于原來(lái)的了。
現(xiàn)在代碼正在運(yùn)行,是時(shí)候測(cè)試它了。
在這一步中,您將為Reverse函數(shù)編寫一個(gè)基本的單元測(cè)試。
a.使用您的文本編輯器,在 fuzz 目錄中創(chuàng)建一個(gè)名為 reverse_test.go 的文件。
b.將以下代碼粘貼到 reverse_test.go 中。
這個(gè)簡(jiǎn)單的測(cè)試將斷言列出的輸入字符串將被正確反轉(zhuǎn)。
使用運(yùn)行單元測(cè)試go test
接下來(lái),您將單元測(cè)試更改為模糊測(cè)試。
單元測(cè)試有局限性,即每個(gè)輸入都必須由開發(fā)人員添加到測(cè)試中。模糊測(cè)試的一個(gè)好處是它可以為您的代碼提供輸入,并且可以識(shí)別您提出的測(cè)試用例沒有達(dá)到的邊緣用例。
在本節(jié)中,您將單元測(cè)試轉(zhuǎn)換為模糊測(cè)試,這樣您就可以用更少的工作生成更多的輸入!
請(qǐng)注意,您可以將單元測(cè)試、基準(zhǔn)測(cè)試和模糊測(cè)試保存在同一個(gè) *_test.go 文件中,但對(duì)于本示例,您將單元測(cè)試轉(zhuǎn)換為模糊測(cè)試。
在您的文本編輯器中,將 reverse_test.go 中的單元測(cè)試替換為以下模糊測(cè)試。
Fuzzing 也有一些限制。在您的單元測(cè)試中,您可以預(yù)測(cè)Reverse函數(shù)的預(yù)期輸出,并驗(yàn)證實(shí)際輸出是否滿足這些預(yù)期。
例如,在測(cè)試用例Reverse("Hello, world")中,單元測(cè)試將返回指定為"dlrow ,olleH".
模糊測(cè)試時(shí),您無(wú)法預(yù)測(cè)預(yù)期輸出,因?yàn)槟鸁o(wú)法控制輸入。
但是,Reverse您可以在模糊測(cè)試中驗(yàn)證函數(shù)的一些屬性。在這個(gè)模糊測(cè)試中檢查的兩個(gè)屬性是:
(1)將字符串反轉(zhuǎn)兩次保留原始值
(2)反轉(zhuǎn)的字符串將其狀態(tài)保留為有效的 UTF-8。
注意單元測(cè)試和模糊測(cè)試之間的語(yǔ)法差異:
(3)確保新包unicode/utf8已導(dǎo)入。
隨著單元測(cè)試轉(zhuǎn)換為模糊測(cè)試,是時(shí)候再次運(yùn)行測(cè)試了。
a.在不進(jìn)行模糊測(cè)試的情況下運(yùn)行模糊測(cè)試,以確保種子輸入通過(guò)。
如果您在該文件中有其他測(cè)試,您也可以運(yùn)行g(shù)o test -run=FuzzReverse,并且您只想運(yùn)行模糊測(cè)試。
b.運(yùn)行FuzzReverse模糊測(cè)試,查看是否有任何隨機(jī)生成的字符串輸入會(huì)導(dǎo)致失敗。這是使用go test新標(biāo)志-fuzz執(zhí)行的。
模糊測(cè)試時(shí)發(fā)生故障,導(dǎo)致問題的輸入被寫入將在下次運(yùn)行的種子語(yǔ)料庫(kù)文件中g(shù)o test,即使沒有-fuzz標(biāo)志也是如此。要查看導(dǎo)致失敗的輸入,請(qǐng)?jiān)谖谋揪庉嬈髦写蜷_寫入 testdata/fuzz/FuzzReverse 目錄的語(yǔ)料庫(kù)文件。您的種子語(yǔ)料庫(kù)文件可能包含不同的字符串,但格式相同。
語(yǔ)料庫(kù)文件的第一行表示編碼版本。以下每一行代表構(gòu)成語(yǔ)料庫(kù)條目的每種類型的值。由于 fuzz target 只需要 1 個(gè)輸入,因此版本之后只有 1 個(gè)值。
c.運(yùn)行沒有-fuzz標(biāo)志的go test; 新的失敗種子語(yǔ)料庫(kù)條目將被使用:
由于我們的測(cè)試失敗,是時(shí)候調(diào)試了。
1、簡(jiǎn)單易學(xué)。
Go語(yǔ)言的作者本身就很懂C語(yǔ)言,所以同樣Go語(yǔ)言也會(huì)有C語(yǔ)言的基因,所以對(duì)于程序員來(lái)說(shuō),Go語(yǔ)言天生就會(huì)讓人很熟悉,容易上手。
2、并發(fā)性好。
Go語(yǔ)言天生支持并發(fā),可以充分利用多核,輕松地使用并發(fā)。 這是Go語(yǔ)言最大的特點(diǎn)。
描述
Go的語(yǔ)法接近C語(yǔ)言,但對(duì)于變量的聲明有所不同。Go支持垃圾回收功能。Go的并行模型是以東尼·霍爾的通信順序進(jìn)程(CSP)為基礎(chǔ),采取類似模型的其他語(yǔ)言包括Occam和Limbo,但它也具有Pi運(yùn)算的特征,比如通道傳輸。
在1.8版本中開放插件(Plugin)的支持,這意味著現(xiàn)在能從Go中動(dòng)態(tài)加載部分函數(shù)。
與C++相比,Go并不包括如枚舉、異常處理、繼承、泛型、斷言、虛函數(shù)等功能,但增加了 切片(Slice) 型、并發(fā)、管道、垃圾回收、接口(Interface)等特性的語(yǔ)言級(jí)支持。
高階函數(shù):
??根據(jù)go語(yǔ)言的數(shù)據(jù)類型的特點(diǎn),可以將一個(gè)函數(shù)作為另一個(gè)函數(shù)的參數(shù)
??fun1(),fun2()
????將fun1函數(shù)作為fun2這個(gè)函數(shù)的參數(shù)。
??fun2函數(shù):高階函數(shù)
????接受了一個(gè)函數(shù)作為參數(shù)的函數(shù),高階函數(shù)
??fun1函數(shù):回調(diào)函數(shù)
????作為另一個(gè)函數(shù)的參數(shù)的函數(shù),叫做回調(diào)函數(shù)
已經(jīng)有好多程序員都把Go語(yǔ)言描述為是一種所見即所得(WYSIWYG)的編程語(yǔ)言。這是說(shuō),代碼要做的事和它在字面上表達(dá)的意思是完全一致的。 在這些新語(yǔ)言中,包含D,Go,Rust和Vala語(yǔ)言,Go曾一度出現(xiàn)在TIOBE的排行榜上面。與其他新語(yǔ)言相比,Go的魅力明顯要大很多。Go的成熟特征會(huì)得到許多開發(fā)者的欣賞,而不僅僅是因?yàn)槠淇浯笃湓~的曝光度。下面我們來(lái)一起探討一下谷歌開發(fā)的Go語(yǔ)言以及談?wù)凣o為什么會(huì)吸引眾多開發(fā)者: 快速簡(jiǎn)單的編譯 Go編譯速度很快,如此快速的編譯使它很容易作為腳本語(yǔ)言使用。關(guān)于編譯速度快主要有以下幾個(gè)原因:首先,Go不使用頭文件;其次如果一個(gè)模塊是依賴A的,這反過(guò)來(lái)又取決于B,在A里面的需求改變只需重新編譯原始模塊和與A相依賴的地方;最后,對(duì)象模塊里面包含了足夠的依賴關(guān)系信息,所以編譯器不需要重新創(chuàng)建文件。你只需要簡(jiǎn)單地編譯主模塊,項(xiàng)目中需要的其他部分就會(huì)自動(dòng)編譯,很酷,是不是? 通過(guò)返回?cái)?shù)值列表來(lái)處理錯(cuò)誤信息 目前,在本地語(yǔ)言里面處理錯(cuò)誤的方式主要有兩種:直接返回代碼或者拋異常。這兩種都不是最理想的處理方式。其中返回代碼是非常令人沮喪的,因?yàn)榉祷氐腻e(cuò)誤代碼經(jīng)常與從函數(shù)中返回的數(shù)據(jù)相沖突。Go允許函數(shù)返回多個(gè)值來(lái)解決這個(gè)問題。這個(gè)從函數(shù)里面返回的值,可以用來(lái)檢查定義的類型是否正確并且可以隨時(shí)隨地對(duì)函數(shù)的返回值進(jìn)行檢查。如果你對(duì)錯(cuò)誤值不關(guān)心,你可以不必檢查。在這兩種情況下,常規(guī)的返回值都是可用的。 簡(jiǎn)化的成分(優(yōu)先于繼承) 通過(guò)使用接口,類型是有資格成為對(duì)象中一員的,就像Java指定行為一樣。例如在標(biāo)準(zhǔn)庫(kù)里面的IO包,定義一個(gè)Writer來(lái)指定一個(gè)方法,一個(gè)Writer函數(shù),其中輸入?yún)?shù)是字節(jié)數(shù)組并且返回整數(shù)類型值或者錯(cuò)誤類型。任何類型實(shí)現(xiàn)一個(gè)帶有相同簽名的Writer方法是對(duì)IO的完全實(shí)現(xiàn),Writer接口。這種是解耦代碼而不是優(yōu)雅。它還簡(jiǎn)化了模擬對(duì)象來(lái)進(jìn)行單元測(cè)試。例如你想在數(shù)據(jù)庫(kù)對(duì)象中測(cè)試一個(gè)方法,在標(biāo)準(zhǔn)語(yǔ)言中,你通常需要?jiǎng)?chuàng)建一個(gè)數(shù)據(jù)庫(kù)對(duì)象,并且需要進(jìn)行大量的初始化和協(xié)議來(lái)模擬對(duì)象。在Go里面,如果該方法需要實(shí)現(xiàn)一個(gè)接口,你可以創(chuàng)建任何對(duì)該接口有用的對(duì)象,所以,你創(chuàng)建了MockDatabase,這是很小的對(duì)象,只實(shí)現(xiàn)了幾個(gè)需要運(yùn)行和模擬的接口——沒有構(gòu)造函數(shù),沒有附件功能,只是一些方法。 簡(jiǎn)化的并發(fā)性 相對(duì)于其他語(yǔ)言,并發(fā)性在Go里面顯得更加容易。把‘go’關(guān)鍵字放在任意函數(shù)前面然后那個(gè)函數(shù)就會(huì)在其go-routine自動(dòng)運(yùn)行(一個(gè)很輕的線程)。go-routines是通過(guò)通道進(jìn)行交流并且基本上封鎖了所有的隊(duì)列消息。普通工具對(duì)相互排斥是有用,但是Go通過(guò)使用通道來(lái)踢掉并發(fā)性任務(wù)和坐標(biāo)更加容易。 優(yōu)秀的錯(cuò)誤消息 所有與Go相似的語(yǔ)言,自身作出的診斷都是無(wú)法與Go相媲美的。例如,一個(gè)死鎖程序,在Go運(yùn)行時(shí)會(huì)通知你目前哪個(gè)線程導(dǎo)致了這種死鎖。編譯的錯(cuò)誤信息是非常詳細(xì)全面和有用的。 其他 這里還有許多其他吸引人的地方,下面就一概而過(guò)的介紹一下,比如高階函數(shù)、垃圾回收、哈希映射和可擴(kuò)展的數(shù)組內(nèi)置語(yǔ)言(部分語(yǔ)言語(yǔ)法,而不是作為一個(gè)庫(kù))等等。 當(dāng)然,Go并不是完美無(wú)瑕。在工具方面還有些不成熟的地方和用戶社區(qū)較小等,但是隨著谷歌語(yǔ)言的不斷發(fā)展,肯定會(huì)有整治措施出來(lái)。盡管許多語(yǔ)言,尤其是D、Rust和Vala旨在簡(jiǎn)化C++并且對(duì)其進(jìn)行簡(jiǎn)化,但它們給人的感覺仍是“C++看上去要更好”。
【Go語(yǔ)言的優(yōu)勢(shì)】
可直接編譯成機(jī)器碼,不依賴其他庫(kù),glibc的版本有一定要求,部署就是扔一個(gè)文件上去就完成了。
靜態(tài)類型語(yǔ)言,但是有動(dòng)態(tài)語(yǔ)言的感覺,靜態(tài)類型的語(yǔ)言就是可以在編譯的時(shí)候檢查出來(lái)隱藏的大多數(shù)問題,動(dòng)態(tài)語(yǔ)言的感覺就是有很多的包可以使用,寫起來(lái)的效率很高。
語(yǔ)言層面支持并發(fā),這個(gè)就是Go最大的特色,天生的支持并發(fā),我曾經(jīng)說(shuō)過(guò)一句話,天生的基因和整容是有區(qū)別的,大家一樣美麗,但是你喜歡整容的還是天生基因的美麗呢?Go就是基因里面支持的并發(fā),可以充分的利用多核,很容易的使用并發(fā)。
內(nèi)置runtime,支持垃圾回收,這屬于動(dòng)態(tài)語(yǔ)言的特性之一吧,雖然目前來(lái)說(shuō)GC不算完美,但是足以應(yīng)付我們所能遇到的大多數(shù)情況,特別是Go1.1之后的GC。
簡(jiǎn)單易學(xué),Go語(yǔ)言的作者都有C的基因,那么Go自然而然就有了C的基因,那么Go關(guān)鍵字是25個(gè),但是表達(dá)能力很強(qiáng)大,幾乎支持大多數(shù)你在其他語(yǔ)言見過(guò)的特性:繼承、重載、對(duì)象等。
豐富的標(biāo)準(zhǔn)庫(kù),Go目前已經(jīng)內(nèi)置了大量的庫(kù),特別是網(wǎng)絡(luò)庫(kù)非常強(qiáng)大,我最愛的也是這部分。
內(nèi)置強(qiáng)大的工具,Go語(yǔ)言里面內(nèi)置了很多工具鏈,最好的應(yīng)該是gofmt工具,自動(dòng)化格式化代碼,能夠讓團(tuán)隊(duì)review變得如此的簡(jiǎn)單,代碼格式一模一樣,想不一樣都很困難。
跨編譯,如果你寫的Go代碼不包含cgo,那么就可以做到window系統(tǒng)編譯linux的應(yīng)用,如何做到的呢?Go引用了plan9的代碼,這就是不依賴系統(tǒng)的信息。
內(nèi)嵌C支持,前面說(shuō)了作者是C的作者,所以Go里面也可以直接包含c代碼,利用現(xiàn)有的豐富的C庫(kù)。