Go 問答彙總篇 二

繼上篇 Go 問答彙總,已經過去了一個多月。今天彙總下近一個多月我關於 Go 的回答。

粗略數了一下,一個多月的時間裏,大約回答了 18 個與 Go 有關的問題,問題主要是來源於 segmentfault 和 zhihu 兩個平臺。後面希望加入更多平臺,如 stackoverflow、github 的感興趣主題。

最近在寫一個小工具,準備用於幫助自己回答不同平臺的問題,同時也便於每個月的問題彙總。寫的有點慢,希望月底可以完成。

正文部分開始。

[golang中如何將redis取出的map[string]string數據解析到目標struct中?](https://www.zhihu.com/questio...

主要和反射相關。

問題主要是關於 map 中如果存在日期字符格式串,如何解析到 time.Time 類型成員中,而對於結構體而言,reflect.Kind() 返回的只能說明字段類型是 struct,並不能確定真正的類型,這時可以用 Go 的 switch type 類型查詢語法實現。

補充一點,在回答中沒有提到的。

在實現 map 到 struct 的通用方法時,我們比較容易想到支持基礎類型,但對於結構體類型而言,可能性太多,如何更靈活地解決問題?我覺得,可通過鉤子方式實現,即如果自定義類型需要支持 map 到 struct 的轉化,可通過在自定義類型上增加鉤子方法實現,比如 UnmarshalMap。如何實現可參考下 encoding/json。

當然,這個工作已經有人做了,參考 github 上的包,mitchellh/mapstructure。前面說的 Hook 也是支持的。

golang 怎麼優雅的實現錯誤碼?

Go 對錯誤處理有一套自己的理念。這個問題,我只是簡單回答了一下,簡單的思路,我定義了用戶級別錯誤和系統級別錯誤。上篇問答彙總也會類似問題。

golang什麼時候該返回error,什麼時候panic?

我的建議是,發生的 error 是否已經嚴重影響服務邏輯,如果在預判之內的錯誤,我們就應該 return error,記錄日誌,並不需要人工干預才能恢復,否則建議 panic。

舉個例子,在一般情況下,服務啓動時,需要進行完善的初始化工作,確認各個組件的運行正常。如果初始化都失敗了,那就沒有必要繼續向下走了,應該 panic 趕緊提示。

Golang time 如何實現的?

問題標題看着挺大,其實題主關心是幾個核心常量之間的轉化關係。主要是三個時間,分別 unix 時間、wall 時間和 absolute 時間。這裏面有個相對重要的轉化公式,在需要考慮平潤年的時候稍微有點複雜。

不多介紹了,具體自己看回答吧。

golang 中時候用指針什麼時候用普通對象?

其實就兩點,一是如果數據結構比較大,建議採用指針,不會發生值拷貝。二是如果需要修改結構的話,必須用指針。當然如果是引用類型,比如 chan、slice、 map,就不用考慮這個問題了。

Golang中的make(T, args)爲什麼返回T而不是*T?

make 針對的是 Go 的引用類型,即 chan、slice 和 map,而 new 針對的指針。引用類型爲什麼 make 不是返回指針呢?這樣一說好像和上個問題有點類似了,當然因爲指針不存在值類型的那些問題。

在循環中 append map 到 map slice,map slice 中的數據全部爲最後一次 append 的數據

與上一個問題知識點類似,map 是引用類型,即使 slice 通過 append 賦值了多份 map 變量,但是其內部指向是同一個地址。

golang中哪些引用類型的指針在聲明時不用加&號,哪些在函數定義的形參和返回值類型中不用*號標註

與前面問題類似,具體看回答。

我的理解,從這裏向前數的四個問題,考察知識點基本類似,簡單點說,就是 make 和 new 和問題。本質上講,就是變量內部就是什麼的問題。

爲什麼 go語言的slice內部函數那麼少?

說實話,我也不明白爲什麼 Go 團隊沒有像爲 string 類型那樣爲 slice 提供相應的標準庫幫助 slice 更方便的操作。但其實,即使沒有這樣的包, slice 常見的各種增刪改查也是可以實現,就是稍微有點 hack。具體如何實現,看看我的問答吧。

golang 等值比較是不是直接比較地址呢?

首先要說 Go 的等值比較比較的是值,而不是地址。Go 中變量的可比較類型是內置的,基本所有類型都可以進行比較,包括 interface 和 struct。兩個變量可比較的提前必須是相同類型。但有一點需要說明的是,interface 是不確定的類型,所有它不但會比較值,還有比較具體的類型。

回答完這個問題後,我突然想起前段時間比較兩個同類型結構體時還用了反射包中 reflect.DeepEqual 方法,真的是浪費資源啊。

golang 中如何禁止一個導出類型直接構造,必須通過new函數來構造?

其他的 oo 語言實現題主要求是非常簡單的,只要定義相應的私有成員屬性並通過構造函數控制輸入的參數即可。

那麼 Go 該如何實現呢?其實也很簡單,思路與 oo 是類似的。只是我們把 oo 語言中的構造函數換成了 Go 中的工廠方法,私有變量變成了 Go 包級別的私有成員屬性。我們只需要通過定義指定的可導出的工廠方法創建實例即可。

入門,進階GO語言,有什麼好的書籍推薦?

我從入門、中級到進階三個階段推薦了幾本書。有興趣的朋友,具體查看回答吧。

如何評價 Go 標準庫中新增的 plugin 包?

這個問題的回答,我是先學先買的。看了 medium 中幾篇關於 plugin 使用案例的文章,總共花了大概三四小時。plugin 包使 Go 是可以實現動態模塊加載的能力,可以在不用重新編譯主程序的情況下加入新功能。這是有一定的價值的。

但 plugin 包也存在一些問題,使用起來會用一些限制因素。但如果我們清楚地瞭解,還是能拎的清我們應該在什麼場景下使用它。具體有啥限制,查看回答吧。

go build 如何隱藏全局靜態字符串變量?

這個問題,我並沒有找到啥好辦法,能想到的就是通過加密解密的方式解決。當然,其實在真實的項目中,我們可以通過引入外部服務實現,比如 k8s 的配置加密功能,使用 ectd 管理配置等。

go語言中, 空的死循環與永遠阻塞的chan細節上有什麼差異?

Goroutine 是搶佔式的,這不同於傳統的協程模型。但它又不是完全的搶佔式,單核的情況下,還是需要 CPU 主動出入資源的,而空死循環將會一直佔用着 CPU,對資源的浪費嚴重,而 chan 阻塞會出讓 CPU 資源,實現併發執行。這應該是兩者最大的不同吧。

除了一般的 chan 實現阻塞,問答還介紹一些其他方式,也可以實現類似的效果。感興趣的朋友可查看回答。

Golang中fmt.Println和直接println有什麼區別?

println 主要是 Go 自己使用,比如源碼、標準庫等,而 fmt 纔是給 Go 開發人員使用的。而且要提的是 println 不能保證兼容性,可能在未來的某一天就不存在了,但 fmt 中的函數就不存在着這樣的問題。

當然,兩者的使用和效果上也是有區別的,如 println 輸出是到標準錯誤的,而非標準輸出。

如何閱讀Golang的源碼?

這個回答是個大工程,零零碎碎花了我差不多三個星期的時間。什麼原因呢?

我提了一個閱讀源碼的思路,分成了大概三步,大致分別是,瞭解使用、熟悉架構和剖析原理。我最近在思考是否自己也開始剖析源碼,於是決定先以第一步入手,把 Go 的源碼整個擼一篇,大概瞭解涉及了的內容和它們的用途。總共涉及四十多個部分,於是花的時間就比較長。

第一步,瞭解使用這一塊,有些部分達到了解使用,但是有些部分只是達到了解的層次。如果要完整閱讀源碼,很難,但大概閱讀還是可行的。準備等等合適時機啓動系統的源碼閱讀的計劃。

golang數據庫操作的時候,需要go func()嗎?跟python異步操作yield有什麼不同?

上篇 Go 問答彙總篇 也有類似問題。我的理解,使用 go func 的前提是必須有可並行執行的任務,這是一個重要前提。

很多時候,大家學 Go 都是衝着 Go 的併發來的,結果學之後發現壓根用不上,很鬱悶啊,總覺得哪裏用的不對,不應該是這樣的。一般的業務開發,特別是 web 的業務開發,使用併發的場景確實不多。而併發性能的問題,服務框架已經幫助我們實現了,完全沒有插手機會,要想真正學會併發,不能只是每天的增刪改查。

彙總完畢!回答如有錯誤,歡迎大家指正。最後,感謝閱讀,彙總篇似乎是比較枯燥的!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章