掃二維碼與項(xiàng)目經(jīng)理溝通
我們在微信上24小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
可以明確的是,Go 沒有非常致命的問題,否則你我他都不會(huì)在這里相遇,也不會(huì)大火。

為樟樹等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計(jì)制作服務(wù),及樟樹網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為成都網(wǎng)站建設(shè)、成都網(wǎng)站制作、樟樹網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長期合作。這樣,我們也可以走得更遠(yuǎn)!
難受的點(diǎn),倒是有不少,今天就由煎魚和大家一起來看看。
在 Go1.18 以前,在所有社交媒體和調(diào)查報(bào)告上來看。Go 最難受的莫過于沒有泛型,
寫一個(gè)通用的方法,要不得把入?yún)⒙暶鳛?interface,要不得寫 N 個(gè)不同類型的一樣代碼的函數(shù),代碼重復(fù)率高。
如下圖:
這是 Go1.18 以前最難受的點(diǎn),現(xiàn)在新版本雖然有了泛型,但現(xiàn)階段配套標(biāo)準(zhǔn)和開源庫還沒完全到位,影響還是會(huì)繼續(xù)存在。
在寫 Go 程序時(shí),我們經(jīng)常要用到 slice、map 等基礎(chǔ)類型。但有一個(gè)比較麻煩的點(diǎn),就是會(huì)涉及到淺拷貝。
一個(gè)不注意就會(huì)引起 BUG,如下代碼:
type T struct {
A string
B []string
}
func main() {
x := T{"煎魚", []string{"上班"}}
y := x
y.A = "咸魚"
y.B[0] = "下班"
fmt.Println(x)
fmt.Println(y)
}輸出結(jié)果是什么?
煎魚到底是上班了,還是下班了?
結(jié)果如下:
{煎魚 [下班]}
{咸魚 [下班]}實(shí)際上在 y := x 時(shí),他拷貝的是指向?qū)ο蟮闹羔?,這個(gè)時(shí)候 x 和 y 的底層數(shù)據(jù)其實(shí)是一家子,自然一變動(dòng) y,x 的煎魚也就下班了。
同類型的 slice 也有 append 的泄露,以及 len、cap 的不準(zhǔn)確問題,是比較折騰人的。
泄露的示例:
var a []int
func f(b []int) []int {
a = b[:2]
return a
}
func main() {
...
}
有興趣的可以具體看《Go 切片導(dǎo)致內(nèi)存泄露,被坑兩次了!》的解析。
在 Go 的錯(cuò)誤處理中,許多小伙伴的難受的點(diǎn)分兩大塊。一個(gè)是大量重復(fù)的 if err != nil 的代碼:
func main() {
x, err := foo()
if err != nil {
// handle error
}
y, err := foo()
if err != nil {
// handle error
}
z, err := foo()
if err != nil {
// handle error
}
s, err := foo()
if err != nil {
// handle error
}
}另外一塊是在異常處理中,Go 現(xiàn)階段是 panic 和 recover 的模式,內(nèi)部還包含 throw 的致命性錯(cuò)誤拋出,無法攔截,為此我也見過個(gè)別事故是因此造成的。
這是一個(gè)爭議性很大的板塊。
我們強(qiáng)行將一段 Go 程序的變量值賦為 nil,并進(jìn)行 nil 與 nil 的判斷。
代碼如下:
func main() {
var v interface{}
v = (*int)(nil)
fmt.Println(v == nil)
}輸出的結(jié)果是什么。是 false,還是 true,又或是拋出異常?
輸出結(jié)果是 fasle,nil 可不 100% 等于 nil。
這與 interface 的內(nèi)部數(shù)據(jù)結(jié)構(gòu)有關(guān),是在編程時(shí)要注意的一個(gè)細(xì)節(jié),具體可詳見《Go 面試題:Go interface 的一個(gè) “坑” 及原理分析》的解析。
Go 非常簡潔,垃圾回收唯一的可調(diào)節(jié)的是 GC 頻率,可以通過 GOGC 變量設(shè)置初始垃圾收集器的目標(biāo)百分比值。
$ GOGC=100 eddycjy
簡單來講就是,GOGC 的值設(shè)置的越大,GC 的頻率越低,但每次最終所觸發(fā)到 GC 的堆內(nèi)存也會(huì)更大。
然后就沒別的方式可以優(yōu)化垃圾回收器本身了,以至于當(dāng)年我還被人拿 Java 來吐槽過一遍,說 Go 肯定有。
壓軸的難受點(diǎn),莫過于 Go 的依賴管理。先是從 GOPATH 時(shí)代,開源后一路水土不服,后面 rsc 直接下場支棱起來硬推。
到 2022 年,目前 Go modules 還是會(huì)存在一些讓人難受的點(diǎn)。甚至曹大總結(jié)了 《Go mod 七宗罪》,不少我在工作中也遇到和替別人解決過,非常的精辟。
引用曹大文章中的 7 點(diǎn):
熟悉掌握 Go 的一個(gè)表現(xiàn),那就是精通 Go modules,不然項(xiàng)目都運(yùn)行的不順利。
今天我們圍繞 Go 的難受場景進(jìn)行了分析和講解,本文涉及的分別是:泛型、淺拷貝和泄露、錯(cuò)誤處理、nil 接口不是 nil、垃圾回收、依賴管理。
其中不少是常見的,也有的是有意而為之(例如:垃圾回收)。從大家的角度來看,你覺得 Go 比較難受的點(diǎn)還有哪些呢?

我們在微信上24小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流