<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在新增新包時,包括預期使用的範例:
當你使用 goroutines
時,要明確它們何時退出或者是否退出。
goroutine
可以通過阻塞通道傳送或接收而洩漏: 即使阻塞的通道不可達,垃圾收集器也不會終止 goroutine
。
即使 goroutine
沒有洩漏,當它們不再被需要時,將它們留在空中也會導致其他微妙和難以診斷的問題。傳送在已關閉的通道時會引發 panic
。“在結果不需要之後”修改仍在使用的輸入仍然會導致資料競爭。並且讓 goroutines
在執行中停留任意長的時間會導致不可預測的記憶體使用。
儘量保持並行程式碼足夠簡單,這樣 goroutine
的生存期就很明顯了。如果這是不可行的,記錄下 goroutines
退出的時間和原因。
有些時候我們使用 goroutine 的時候,會忘記捕獲 panic,這裡提供一個封裝好了的 go
方法:
// GoSafe runs the given fn using another goroutine, recovers if fn panics. func GoSafe(log *log.Logger, fn func()) { go RunSafe(log, fn) } // RunSafe runs the given fn, recovers if fn panics. func RunSafe(log *log.Logger, fn func()) { defer Recover(log) fn() } // Recover is used with defer catch panics. func Recover(log *log.Logger) { if p := recover(); p != nil { log.Error("%sn%s", p, debug.Stack()) } }
不要使用 _
變數丟棄錯誤。如果函數返回錯誤,請檢查它以確保函數成功。處理錯誤,返回錯誤,或者,在真正異常的情況下,丟擲 panic
。
可以參考官方檔案中優雅的做法:Effective Go
避免重新命名匯入,除非是為了避免名稱衝突
好的包名不需要重新命名。如果發生衝突,最好重新命名、原生的或特定於專案的匯入。
匯入按組區分,組與組之間有空白行。標準庫包總是在第一組中。
package main import ( "fmt" "hash/adler32" "os" "appengine/foo" "appengine/user" "github.com/foo/bar" "rsc.io/goversion/version" )
使用 goimport 能幫助到您,所以在專案中設定 goimport 是必要的。
僅為其副作用而匯入的包(使用import _ "pkg"語法)應該只在程式的主包中匯入,或在需要它們的測試中匯入。
類似使用其他包的 init
函數
import .
在解決迴圈依賴時較為好用的方式,但是不能濫用:
package foo_test import ( "bar/testutil" // also imports "foo" . "foo" )
在這種情況下,測試檔案不能在包 foo
中,因為它使用 bar/testutil
,它匯入 foo
。所以我們使用 'import .
' 形式讓檔案假裝是包 foo
的一部分,即使它不是。除了這種情況,不要使用import .
在你的專案中。它使程式更加難以閱讀,因為不清楚像 Quux
這樣的名稱是當前包還是匯入包中的頂級識別符號。
在 C
和類似的語言中,函數通常會返回 -1 或 null 這樣的值來表示錯誤或預設結果:
// Lookup returns the value for key or "" if there is no mapping for key. func Lookup(key string) string // Failing to check for an in-band error value can lead to bugs: Parse(Lookup(key)) // returns "parse failure for value" instead of "no value for key"
Go
對多個返回值的支援提供了更好的解決方案。與其要求使用者端檢查帶內錯誤值,函數應該返回一個額外的值來指示它的其他返回值是否有效。這個返回值可能是一個錯誤,也可能是一個不需要解釋的布林值。它應該是最終的返回值。
// Lookup returns the value for key or ok=false if there is no mapping for key. func Lookup(key string) (value string, ok bool)
這可以防止呼叫者錯誤地使用返回值:
Parse(Lookup(key)) // compile-time error
並鼓勵更健壯和可讀的程式碼:
value, ok := Lookup(key) if !ok { return fmt.Errorf("no value for %q", key) } return Parse(value)
該規則適用於匯出函數,但也適用於私有函數。
當它們是函數的有效結果時,像 nil、""、0 和 -1 這樣的值是可以的,也就是說,當呼叫者不需要以不同於其他值的方式處理它們時。
一些標準庫函數,比如包 strings
中的函數,返回帶內錯誤值。這極大地簡化了字串操作程式碼,但代價是需要程式設計師付出更多努力。一般來說,Go程式碼應該返回額外的錯誤值。
儘量將正常的程式碼路徑縮排到最小,並縮排錯誤處理,首先處理它。這通過允許快速視覺掃描正常路徑提高了程式碼的可讀性。例如,不要寫:
if err != nil { // error handling } else { // normal code }
相反,寫:
if err != nil { // error handling return // or continue, etc. } // normal code
如果語句中有初始化語句,例如:if
if x, err := f(); err != nil { // error handling return } else { // use x }
然後,這可能需要將短變數宣告移動到它自己的行:
x, err := f() if err != nil { // error handling return } // use x
名字中屬於首字母縮寫或首字母縮寫的詞(例如:"URL"
或"NATO"
)的大小寫是一致的。例如,"URL"
應該顯示為 "URL"
或 "url"
(如"urlPony"
或"URLPony"
),而不是"Url"
。例如:ServeHTTP
而不是ServeHttp
。對於具有多個初始化“單詞”的識別符號,可以使用例如"xmlHTTPRequest"
或"XMLHTTPRequest"
。
當"ID"
是"identifier"
的縮寫時,這個規則也適用於"ID"
(在大多數情況下,它不是"ego"
、"superego"
中的"ID"
),所以寫"appID"
而不是"appId"
。
protobuf
生成的程式碼不受此規則約束。人類編寫的程式碼要比機器編寫的程式碼具有更高的標準。
Go
介面通常屬於使用介面型別值的包,而不是實現這些值的包。實現包應該返回具體的(通常是指標或結構)型別:這樣,新的方法就可以新增到實現中,而不需要大量的重構。
不要在API的實現者端定義 "mock"
介面;相反,應該設計API,以便可以使用實際實現的公共API進行測試。
不要在使用之前定義介面:沒有一個實際的使用範例,很難判斷介面是否必要,更不用說它應該包含哪些方法了。(有點重構的意思,將已有的方法抽象起來)
package consumer // consumer.go type Thinger interface { Thing() bool } func Foo(t Thinger) string { … }
package consumer // consumer_test.go type fakeThinger struct{ … } func (t fakeThinger) Thing() bool { … } … if Foo(fakeThinger{…}) == "x" { … }
// DO NOT DO IT!!! package producer type Thinger interface { Thing() bool } type defaultThinger struct{ … } func (t defaultThinger) Thing() bool { … } func NewThinger() Thinger { return defaultThinger{ … } }
相反,返回一個具體型別,並讓使用者模擬生產者實現。
package producer type Thinger struct{ … } func (t Thinger) Thing() bool { … } func NewThinger() Thinger { return Thinger{ … } }
在Go程式碼中沒有嚴格的行長限制,但是要避免令人不舒服的長行。類似地,當行更長的時候,不要新增換行符以保持行短——例如,如果它們是重複的。
大多數情況下,當人們“不自然地”換行時(或多或少地在函數呼叫或函數宣告中換行,儘管存在一些異常),如果它們有合理數量的引數和合理較短的變數名,換行將是不必要的。較長的行似乎和較長的名字聯絡在一起,去掉長名字會有很大幫助。
換句話說,斷行是因為你所寫的內容的語意(作為一般規則),而不是因為行長。如果您發現這產生了太長行,那麼更改名稱或語意,您可能會得到一個好的結果。
實際上,這與函數的長度是完全相同的。沒有“函數永遠不會超過N行的規則”,但確實存在過長的函數,以及重複過小的函數,解決方法是改變函數的邊界,而不是開始計數行數。
Mixed Caps
想想在 godoc
中會是什麼樣子。命名結果引數如下:
func (n *Node) Parent1() (node *Node) {} func (n *Node) Parent2() (node *Node, err error) {}
將在 godoc
中重複;更好的使用:
func (n *Node) Parent1() *Node {} func (n *Node) Parent2() (*Node, error) {}
另一方面,如果函數返回兩個或三個相同型別的引數,或者如果從上下文不清楚結果的含義,新增名稱在某些上下文中可能是有用的。不要為了避免在函數內部宣告 var 而命名結果引數;以不必要的API冗長為代價來換取較小的實現簡便性。
func (f *Foo) Location() (float64, float64, error)
不如:
// Location returns f's latitude and longitude. // Negative values mean south and west, respectively. func (f *Foo) Location() (lat, long float64, err error)
如果函數只有幾行,裸返回是可以的。一旦它是一箇中等大小的函數,就要顯式地顯示返回值。推論:僅僅因為結果引數允許使用裸返回而命名結果引數是不值得的。清晰的檔案總是比在函數中節省一兩行更重要。
最後,在某些情況下,您需要命名結果引數,以便在延遲閉包中更改它。這總是可以的。
沒有引數的語句返回指定的返回值。這就是所謂的“裸返回”。
func split(sum int) (x, y int) { x = sum * 4 / 9 y = sum - x return }
包註釋,像 godoc
提供的所有註釋一樣,必須出現在 package
的上面,不能有空行。
// Package math provides basic constants and mathematical functions. package math
/* Package template implements data-driven templates for generating textual output such as HTML. .... */ package template
對於 "package main" 註釋,其他風格的註釋在二進位制名稱之後也可以(如果它在前面,則可以大寫),例如,對於您可以編寫的目錄中的
// Binary seedgen ... package main
// Command seedgen ... package main
// Program seedgen ... package main
// The seedgen command ... package main
// The seedgen program ... package main
// Seedgen .. package main
這些都是例子,合理的變體也是可以接受的。
注意,以小寫單詞開頭的句子不屬於包註釋的可接受選項,因為它們是公開可見的,應該用正確的英語編寫,包括句子的第一個單詞大寫。當二進位制名稱是第一個單詞時,即使它與命令列呼叫的拼寫不嚴格匹配,也需要將其大寫。
struct
每個結構體必須有自己的建構函式,並且使用 options 模式來構建新的引數。
以上就是go code review 程式碼偵錯的詳細內容,更多關於go code review的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45