偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Go 語言代碼風(fēng)格規(guī)范-指南篇

開發(fā) 前端
如果一個(gè)更改會(huì)讓現(xiàn)有的風(fēng)格偏差惡化,在更多的 API 層面被暴露出來,擴(kuò)大存在偏差的文件數(shù)量,或引入了一個(gè)實(shí)際的 bug,那么對(duì)于新代碼而言,局部一致性不再是違反風(fēng)格指南的有效理由。

?每門開發(fā)語言都會(huì)有其特有的風(fēng)格規(guī)范(亦或指南),開發(fā)者遵循規(guī)范能帶來顯著收益,有效促進(jìn)團(tuán)隊(duì)協(xié)作、減少 bug 錯(cuò)誤、降低維護(hù)成本等。

Google 開源的 Google Style Guides (?https://google.github.io/styleguide/?)為多種編程語言提供了風(fēng)格規(guī)范,包括 C++、Java、Python、JavaScript 等。在 2022 年 11 月,Go 語言風(fēng)格規(guī)范(?https://google.github.io/styleguide/go/index)也終于得到開源。

Google 發(fā)布的 Go 語言風(fēng)格規(guī)范一共包括四部分內(nèi)容。

  • 概述篇:https://google.github.io/styleguide/go/index
  • 指南篇:https://google.github.io/styleguide/go/guide
  • 決策篇:https://google.github.io/styleguide/go/decisions
  • 最佳實(shí)踐篇:https://google.github.io/styleguide/go/best-practices

如果你所在的團(tuán)體還未形成一套系統(tǒng)的 Go 風(fēng)格規(guī)范,不妨參考這份指南。

風(fēng)格原則

這里列舉了一些總體原則,它們總結(jié)了思考如何編寫可讀性 Go 代碼。以下是根據(jù)重要性排序的可讀性代碼特性。

  • 清晰性:對(duì)讀者來說,代碼的目的和基本原理是清楚的。
  • 簡單性:代碼以盡可能簡單的方式實(shí)現(xiàn)其目標(biāo)。
  • 簡潔性:代碼具有高信噪比。
  • 可維護(hù)性:編寫的代碼易于維護(hù)。
  • 一致性:代碼與更廣泛的 Google 代碼庫風(fēng)格一致。

1. 清晰性

可讀性的核心目標(biāo)是編寫對(duì)讀者而言清晰的代碼。

清晰主要是通過有效的命名、有用的注釋和高效的代碼組織來實(shí)現(xiàn)的。

清晰性應(yīng)該是從讀者的角度來看,而非代碼編寫者。代碼易于閱讀比易于編寫更重要。代碼清晰性有兩個(gè)不同的方面:

  • 代碼實(shí)際上在做什么?
  • 為什么代碼會(huì)做它所做的事情?

代碼實(shí)際上在做什么?

Go 的設(shè)計(jì)使得它應(yīng)該相對(duì)直接地看到代碼在做什么。在存在不確定或者讀者需要先驗(yàn)知識(shí)才能理解代碼的情況下,這值得花時(shí)間讓未來的讀者更清晰地了解代碼的用途。例如,以下措施可能會(huì)有助于提供更清晰的代碼:

  • 使用更具描述性的變量名
  • 添加附加注釋
  • 用空格和注釋分解代碼
  • 將代碼重構(gòu)為單獨(dú)的函數(shù)/方法,使其更加模塊化

這里沒有放之四海而皆準(zhǔn)的方法,但在開發(fā) Go 代碼時(shí)優(yōu)先考慮清晰性很重要。

為什么代碼會(huì)做它所做的事情?

代碼的基本原理通常通過變量、函數(shù)、方法或包的名稱充分傳達(dá)。如果沒有,添加注釋很重要。當(dāng)代碼包含了讀者可能不熟悉的細(xì)微差別時(shí),解釋”為什么“就顯得尤為重要。例如:

  • 語言上的細(xì)微差別,例如,閉包要獲取一個(gè)循環(huán)變量,但是代碼寫在很多行之外。
  • 業(yè)務(wù)邏輯的細(xì)微差別,例如,需要區(qū)分實(shí)際用戶和冒充用戶的訪問控制檢查。

某個(gè) API 可能需要額外注意才能正確使用。例如,出于性能原因,一段代碼可能錯(cuò)綜復(fù)雜且難以理解,或者一系列復(fù)雜的數(shù)學(xué)運(yùn)算可能以意想不到的方式使用類型轉(zhuǎn)換。在這些場(chǎng)景以及更多類似的情況下,重要的是要有隨附的注釋和文檔來解釋它們,這樣以后的維護(hù)者才不會(huì)犯錯(cuò)誤,這些讀者能夠不用進(jìn)行逆向工程而理解代碼。

同樣重要的是要注意到,一些為了提供清晰性的嘗試(例如添加額外的注釋)可能會(huì)模糊代碼的實(shí)際目的,例如增加混亂、重復(fù)描述代碼、與代碼自相矛盾的注釋,或者為了保證注釋最新而增加維護(hù)負(fù)擔(dān)。讓代碼自己說話(例如,通過使用可自描述的符號(hào)名稱)而不是添加多余的注釋。注釋通常最好是解釋為什么做某事,而不是代碼在做什么。

Google 代碼庫在很大程度上是統(tǒng)一與一致的。通常情況下,與眾不同的代碼(例如,通過使用不熟悉的模式)那樣做是有充分理由的,通常是為了性能考慮。保持這一特性很重要,它可以讓讀者清楚地知道在閱讀一段新代碼時(shí)他們應(yīng)該把注意力集中在什么地方。。

標(biāo)準(zhǔn)庫包含許多實(shí)踐該原則的示例。例如其中:

  • sort 包中的維護(hù)者注釋。
  • 同樣在 sort 包中有一些很好且可運(yùn)行的例子,它們同時(shí)有利于使用者(例子在[godoc](sort package - sort - Go Packages)顯示)和維護(hù)者(作為部分測(cè)試用途的例子)。
  • strings.Cut 雖然只有四行代碼,但它們提高了對(duì)調(diào)用者而言,使用時(shí)的清晰性和正確性。

2. 簡單性

對(duì)于那些使用、閱讀和維護(hù)它的人來說,你的 Go 代碼應(yīng)該是簡單的。

Go 代碼應(yīng)該以實(shí)現(xiàn)其目標(biāo)的最簡單方式編寫,無論是在行為還是性能方面。在 Google Go 代碼庫中,簡單的代碼意味著:

  • 易于從上到下閱讀
  • 不假設(shè)你已經(jīng)提前知道它在做什么
  • 不假設(shè)你可以記住前面的所有代碼
  • 沒有不必要的抽象層次
  • 沒有引起人們對(duì)普通事物的注意的名字
  • 使讀者清楚值和決策的傳播情況
  • 有注釋解釋為什么而不是什么,以及代碼正在做什么以避免以后的偏差
  • 有獨(dú)立的文檔
  • 有有用的錯(cuò)誤和有用的失敗測(cè)試用例
  • 可能經(jīng)常與“故作聰明”的代碼相互排斥

在代碼簡單性和 API 使用簡單性之間可能會(huì)出現(xiàn)權(quán)衡。例如,讓代碼更復(fù)雜可能是值得的,這樣 API 的終端用戶可以更容易且正確地調(diào)用 API。相比之下,為 API 的終端用戶留一些額外的工作也可能是值得的,這樣代碼仍然簡單易懂。

當(dāng)代碼需要復(fù)雜性時(shí),應(yīng)該刻意地增加復(fù)雜性。如果需要額外的性能,或者一個(gè)特定的庫或服務(wù)有多個(gè)不同的用戶,這通常是必要的。復(fù)雜性應(yīng)該是合理的,但它應(yīng)該隨附文檔,以便用戶和未來的維護(hù)者能夠理解和駕馭復(fù)雜度。這應(yīng)該輔以證明其正確用法的測(cè)試和示例,尤其是在同時(shí)存在“簡單”和“復(fù)雜”代碼使用方式的情況下。

我們力求避免代碼庫中不必要的復(fù)雜性,以便當(dāng)復(fù)雜性確實(shí)出現(xiàn)時(shí),它表明這些相關(guān)代碼需要仔細(xì)理解和維護(hù)。理想情況下,應(yīng)該附有注釋,它解釋基本原理并確定應(yīng)注意的事項(xiàng)。在優(yōu)化代碼以提高性能時(shí)經(jīng)常會(huì)出現(xiàn)這種情況;這樣做通常需要更復(fù)雜的方法,比如預(yù)分配緩沖區(qū)并在 goroutine 的整個(gè)生命周期中重用它。當(dāng)維護(hù)者看到它時(shí),這應(yīng)該是一個(gè)線索,表明相關(guān)代碼是性能的關(guān)鍵代碼,未來對(duì)該段代碼進(jìn)行修改時(shí)應(yīng)該持有謹(jǐn)慎態(tài)度。另一方面,如果使用不當(dāng),這種復(fù)雜性會(huì)給那些將來需要閱讀或更改代碼的人帶來負(fù)擔(dān)。

如果代碼的目的很簡單但最終實(shí)現(xiàn)卻很復(fù)雜,這通常是應(yīng)該重新查看實(shí)現(xiàn)以確定是否有更簡單的方式來完成相同目的的信號(hào)。

最少機(jī)制

如果有多種方式可以表達(dá)相同的想法,請(qǐng)選擇使用最標(biāo)準(zhǔn)的一種。復(fù)雜的機(jī)制常在,但不應(yīng)無故使用。根據(jù)需要而增加代碼的復(fù)雜性很容易,而在發(fā)現(xiàn)不必要的復(fù)雜性后,消除現(xiàn)有的復(fù)雜性要困難得多。

在足以滿足你的用例時(shí),使用核心語言結(jié)構(gòu)(例如 slice、map、循環(huán)或 struct)。

如果沒有,請(qǐng)?jiān)跇?biāo)準(zhǔn)庫中尋找一種工具(如 HTTP 客戶端或模板引擎)。

最后,在引入新的依賴項(xiàng)或自己造輪子之前,請(qǐng)考慮 Google 代碼庫中是否有對(duì)應(yīng)的核心庫。

例如,考慮包含綁定到具有默認(rèn)值的變量的標(biāo)志的生產(chǎn)環(huán)境代碼,該默認(rèn)值必須在測(cè)試中被覆蓋。除非打算測(cè)試程序的命令行界面本身(例如,使用 os/exec?),否則直接覆蓋綁定值比使用 flag.Set? 更簡單,也更可取。類似地,如果一段代碼需要對(duì)集合成員進(jìn)行檢查,那么一個(gè)布爾值類型的 map(map[string]bool)通常就足夠了。僅當(dāng)需要更復(fù)雜的操作而 map 無法實(shí)現(xiàn)或使用起來過于復(fù)雜,才應(yīng)使用提供類集合類型和功能的庫。

3. 簡潔性

簡潔的 Go 代碼具有很高的信噪比。應(yīng)該很容易地辨別相關(guān)細(xì)節(jié),它通過命名和代碼結(jié)構(gòu)引導(dǎo)讀者去詳細(xì)了解。

在任何時(shí)候,都會(huì)有很多東西阻礙代碼呈現(xiàn)最主要的細(xì)節(jié):

  • 重復(fù)代碼
  • 外來語法
  • 晦澀難懂的名字
  • 不必要的抽象
  • 空格

重復(fù)的代碼模糊了每個(gè)幾乎相同部分之間的差異,它需要讀者通過視覺比較相似的代碼行已找到變化的地方。表格驅(qū)動(dòng)測(cè)試室一個(gè)很好的機(jī)制示例,它可以從每次重復(fù)的重要細(xì)節(jié)中簡明地提取出通用代碼,但是選擇將哪些部分包含在表格中將影響表格的易懂程度。

在考慮多種方式組織代碼時(shí),需要考慮哪種方式能讓重要的細(xì)節(jié)最明顯。

理解和使用常見的代碼結(jié)構(gòu)和正宗用法對(duì)于保持高信噪比也很重要。例如下面的代碼塊在錯(cuò)誤處理中很常見,讀者可以很快理解這塊的用途。

// Good:
if err := doSomething(); err != nil {
// ...
}

如果代碼看起來與此非常相似但略有不同,讀者可能不會(huì)注意到變化。在這種情況下,值得通過添加注釋以引起注意,來有意“增強(qiáng)”錯(cuò)誤檢查的信號(hào)。

// Good:
if err := doSomething(); err == nil { // if NO error
// ...
}

4. 可維護(hù)性

代碼被編輯的次數(shù)比它編寫的次數(shù)多得多。具有可讀性的代碼不僅對(duì)試圖理解其工作原理的讀者有意義,而且對(duì)需要更改它的程序員也有意義。清晰性是關(guān)鍵。

  • 可維護(hù)性的代碼:
  • 易于被未來的程序員正確地修改
  • 具有結(jié)構(gòu)化的 API,以便它們可以優(yōu)雅地增長
  • 清楚代碼所做的假設(shè),它選擇對(duì)應(yīng)到問題結(jié)構(gòu)的抽象,而不是對(duì)應(yīng)到代碼結(jié)構(gòu)
  • 避免不必要的耦合,不包含未使用的功能
  • 有一個(gè)全面的測(cè)試套件,以確保承諾的行為得到維護(hù),重要的邏輯是正確的,并且測(cè)試用例失敗時(shí)能提供清晰、可操作的診斷。

當(dāng)使用像接口和類型這樣的抽象時(shí),根據(jù)定義從它們使用的上下文中刪除信息,重要的是要確保它們提供了足夠的好處。編輯器和 IDE 可以直接連接到方法定義并在使用具體類型時(shí)顯示相應(yīng)的文檔,但在其他情況下只能參考對(duì)應(yīng)的接口定義。接口是一個(gè)強(qiáng)大的工具,但使用它也有代價(jià),因?yàn)榫S護(hù)者可能需要了解底層實(shí)現(xiàn)的細(xì)節(jié)才能正確使用接口,這必須在接口文檔或調(diào)用處進(jìn)行解釋。

可維護(hù)的代碼也避免了將重要的細(xì)節(jié)隱藏在容易被忽視的地方。例如,在以下的代碼例子中,一個(gè)字符的存在都會(huì)對(duì)理解代碼產(chǎn)生重大的影響。

// Bad:
// The use of = instead of := can change this line completely.
if user, err = db.UserByID(userID); err != nil {
// ...
}
// Bad:
// The ! in the middle of this line is very easy to miss.
leap := (year%4 == 0) && (!(year%100 == 0) || (year%400 == 0))

這些都并非不正確,但都可以以更明確的方式編寫,或者可以附帶注釋以引起對(duì)重要行為的注意。

// Good:
u, err := db.UserByID(userID)
if err != nil {
return fmt.Errorf("invalid origin user: %s", err)
}
user = u
// Good:
// Gregorian leap years aren't just year%4 == 0.
// See https://en.wikipedia.org/wiki/Leap_year#Algorithm.
var (
leap4 = year%4 == 0
leap100 = year%100 == 0
leap400 = year%400 == 0
)
leap := leap4 && (!leap100 || leap400)

同樣的,一個(gè)隱藏了關(guān)鍵邏輯或者重要邊緣情況的輔助函數(shù)會(huì)很容易地使得之后的更改中可能沒有合適地考慮到它。

可預(yù)測(cè)的命名是可維護(hù)代碼的另一個(gè)特征。包的用戶或一段代碼的維護(hù)者應(yīng)該能夠預(yù)測(cè)給定上下文中的變量、方法或函數(shù)的名稱。相同概念的函數(shù)參數(shù)和接收者通常應(yīng)該共享相同的名稱,這既可以使文檔易于理解,也可以以最小的開銷促進(jìn)代碼重構(gòu)。

可維護(hù)代碼應(yīng)最小化其依賴性(隱式和顯式)。依賴更少的包意味著可以影響行為的代碼行更少。避免對(duì)內(nèi)部或者沒有文檔記錄的行為的依賴,在將來這些行為發(fā)生改變時(shí),這些代碼就不太可能會(huì)成為維護(hù)負(fù)擔(dān)。

在考慮如何組織或編寫代碼時(shí),值得花時(shí)間去思考代碼可能隨時(shí)間的推移而演進(jìn)的方式。如果給定的方法更有利于未來更簡單、更安全的更改,那通常是一個(gè)很好的權(quán)衡,即使這意味著設(shè)計(jì)稍微復(fù)雜一些。

5. 一致性

一致的代碼是在更廣泛的代碼庫中、在團(tuán)隊(duì)或包的上下文中,甚至在同一個(gè)文件中,看起來、感覺和行為都類似的代碼。

一致性問題不會(huì)凌駕于上述任何原則,但如果必須打破平衡,那么打破平衡以保持一致性通常是有益的。

包內(nèi)的一致性通常是最直接重要的一致性級(jí)別。如果同一個(gè)問題在包中以多種方式處理,或者如果相同概念在一個(gè)文件中有多個(gè)名稱,則可能會(huì)非常不協(xié)調(diào)。但是,即使這樣也不應(yīng)該凌駕于文檔化的風(fēng)格原則或全局一致性之上。

核心指南

這些指南收集了所有 Go 代碼都應(yīng)遵循的 Go 風(fēng)格最重要的方面。我們希望在編寫可讀性代碼的時(shí)候?qū)W習(xí)并遵循這些準(zhǔn)則。這些準(zhǔn)則預(yù)計(jì)不會(huì)被經(jīng)常更改,并且新添加的內(nèi)容必須被高標(biāo)準(zhǔn)審核。

下面的指南擴(kuò)展了 Effective Go 中的建議,這些建議為整個(gè)社區(qū)的 Go 代碼提供了一個(gè)共同的基線。

格式化

所有 Go 源文件必須符合 gofmt 工具輸出的格式。此格式由 Google 代碼庫中的提交前檢查強(qiáng)制執(zhí)行。生成的代碼通常也應(yīng)該格式化(例如,通過使用 format.Source),因?yàn)樗部梢栽诖a搜索中瀏覽。

駝峰命名

Go 源代碼在編寫多詞名稱時(shí)使用 MixedCaps 或mixedCaps (駝峰命名) 而不是下劃線 (蛇式)。

即使它打破了其他語言的約定,這也適用。例如,常量如果是可導(dǎo)出的,則為 MaxLength(而非 MAX_LENGTH),如果為未導(dǎo)出的,則為 maxLength(而非 max_length)。

為了首字母大寫為可導(dǎo)出的目的,局部變量被視為未導(dǎo)出的。

代碼行長度

Go 源代碼沒有固定的代碼行長度。如果一行感覺太長,應(yīng)該考慮重構(gòu)而不是折斷。如果它已經(jīng)盡可能短,那么應(yīng)該允許該代碼行保持變長。

不要分割代碼行的情況:

  • 在縮進(jìn)更改之前(例如,函數(shù)聲明、條件)
  • 使某個(gè)長字符串(例如 URL)適合多個(gè)較短的行

命名

命名與其說是科學(xué),不如說是一門藝術(shù)。在 Go 中,名稱往往比許多其他語言短一些,但適用相同的一般準(zhǔn)則。命名時(shí)應(yīng)該注意:

  • 使用時(shí)不會(huì)感到重復(fù)
  • 考慮上下文
  • 不再重復(fù)已經(jīng)清楚的概念

你可以在【決策篇】中找到更多關(guān)于命名的具體指導(dǎo)。

局部一致性

在風(fēng)格指南沒有提及特定風(fēng)格點(diǎn)的地方,作者可以自由選擇他們喜歡的風(fēng)格,除非代碼非常接近的地方(通常在同一個(gè)文件或包中,但有時(shí)在團(tuán)隊(duì)或項(xiàng)目目錄中) 在該問題上采取了一致的風(fēng)格。

有效的局部風(fēng)格考量的例子:

  • 使用 %s 或 %v 格式化打印錯(cuò)誤
  • 使用緩存 channel 代替互斥鎖

無效的局部風(fēng)格考量的例子:

  • 代碼行長度限制
  • 使用基于斷言的測(cè)試庫

如果局部風(fēng)格與風(fēng)格指南不一致,但可讀性影響僅限于一個(gè)文件,它通常會(huì)在代碼審查中浮出水面,一致的修復(fù)將超出相關(guān) CL(change list,變更清單) 的范圍。那時(shí),提交一個(gè) bug 以追蹤該修復(fù)是合適的。

如果一個(gè)更改會(huì)讓現(xiàn)有的風(fēng)格偏差惡化,在更多的 API 層面被暴露出來,擴(kuò)大存在偏差的文件數(shù)量,或引入了一個(gè)實(shí)際的 bug,那么對(duì)于新代碼而言,局部一致性不再是違反風(fēng)格指南的有效理由。在這些情況下,作者應(yīng)該在同一個(gè) CL 下清理現(xiàn)有的代碼庫,在當(dāng)前 CL 之前進(jìn)行代碼重構(gòu),或者找到一個(gè)至少不會(huì)使得局部問題變得更糟的替代方案。?

責(zé)任編輯:武曉燕 來源: Golang技術(shù)分享
相關(guān)推薦

2022-11-28 08:15:14

Go語言代碼

2023-11-22 08:00:56

Go命名規(guī)范

2019-10-15 14:16:45

編程語言Go 開發(fā)

2021-11-08 07:48:48

Go語言對(duì)象

2022-03-25 21:57:49

匯編Go語言

2021-05-06 11:04:55

GooglePython代碼

2022-05-09 10:36:05

PythonPyScript開發(fā)者

2024-10-08 05:00:00

PEP 8編碼Python

2012-11-20 10:20:57

Go

2017-01-12 14:55:50

JavaScript編程

2020-03-18 15:54:41

開發(fā)效率代碼

2025-03-20 07:01:40

2025-03-28 07:50:00

端到端測(cè)試Go語言

2023-11-01 13:37:38

Golang代碼

2020-11-30 06:17:03

Go語言

2020-11-26 06:40:24

Go語言基礎(chǔ)

2020-12-02 08:45:36

Go語言

2020-11-23 08:54:14

Go語言結(jié)構(gòu)體

2022-01-17 07:50:37

Go代碼規(guī)范

2017-02-13 13:14:07

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)