這篇文章主要講解了“如何編寫Go語言庫”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“如何編寫Go語言庫”吧!
成都創(chuàng)新互聯(lián)主要從事成都網(wǎng)站制作、成都網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)岳陽縣,10余年網(wǎng)站建設(shè)經(jīng)驗(yàn),價格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):18980820575
不要對 HTTP 客戶端硬編碼
很對庫都包含了對 http.DefaultClient 的硬編碼。雖然對庫本身來說這并不是問題,但是庫的作者并未理解應(yīng)該怎樣使用 http.DefaultClient 。正如 default client 建議它只在用戶沒有提供其他 http.Client 時才被使用。相反的是,許多庫作者樂意在他們代碼中涉及 http.DefaultClient 的部分采用硬編碼,而不是將它作為一個備選。這會導(dǎo)致在某些情況下這個庫不可用。
首先,我們很多人都讀過這篇講述 http.DefaultClient 不能自定義超時時間的文章《Don’t use Go’s default HTTP client (in production)[1]》,當(dāng)你沒法保證你的HTTP 請求一定會完成(或者至少要等一個完全無法預(yù)估時間的響應(yīng))時,你的程序可能會遇到奇怪的 goroutine 泄漏和一些無法預(yù)知的行為。在我看來,這會使每一個對 http.DefaultClient 采用硬編碼的庫不可用。
其次,網(wǎng)絡(luò)需要一些額外的配置。有時候需要用到代理,有時候需要對 URL 進(jìn)行一丟丟的改寫,甚至可能 http.Transport 需要被一個定制的接口替換。當(dāng)一個程序員在你的庫里用他們自己的 http.Client 實(shí)例時,以上這些都很容易被實(shí)現(xiàn)。
在你的庫中處理 http.Client 的推薦方式是使用提供的客戶端,但是如果需要的話,有一個默認(rèn)的備選:
func CreateLibrary(client *http.Client) *Library { if client == nil { client = http.DefaultClient } ...}
或者如果你想從工廠函數(shù)中移除參數(shù),請?jiān)谀愕?struct 中定義一個輔助方法,并且讓用戶在需要時設(shè)置其屬性:
type Library struct { Client *http.Client}func (l *Library) getClient() *http.Client { if l.Client == nil { return http.DefaultClient } return l.Client}
另外,如果一些全局的特性對于每個請求來講都是必須的,人們經(jīng)常感覺到需要用他們自己的實(shí)例來替換 http.Client。這是一個錯誤的方法 — 如果你需要在你的請求中設(shè)置一些額外的 headers,或者在你的客戶端引入某類公共的特性,你只需要簡單為每個請求進(jìn)行設(shè)置或者用組裝定制客戶端的方式來代替完全替換它。
不要引入全局變量
另一個反面模式是允許用戶在一個庫中設(shè)置全局變量。舉個例子,在你的庫中允許用戶設(shè)置一個全局的 http.Client 并被所有的 HTTP 調(diào)用執(zhí)行:
var libraryClient *http.Client = http.DefaultClientfunc SetHttpClient(client *http.Client) { libraryClient = client}
通常在一個庫中不應(yīng)該存在一堆全局變量。當(dāng)你寫代碼的時候,你應(yīng)該想想用戶在他們的程序中多次使用你的這個庫會發(fā)生什么。全局變量會使不同的參數(shù)沒有辦法被使用。而且,在你的代碼中引入全局變量會引起測試上的問題并造成代碼上不必要的復(fù)雜度。使用全局變量可能會導(dǎo)致在你程序的不同模塊有不必要的依賴。在寫你的庫的時候,避免全局狀態(tài)是格外重要的。
返回 structs,而不是 interfaces
這是一個普遍的問題(實(shí)際上我在這一點(diǎn)上也犯過錯)。很多庫都有下面這類函數(shù):
func New() LibraryInterface { ...}
在上面的 case 中,返回一個 interface 使 struct 的特性在庫里被隱藏了。實(shí)際上應(yīng)該這么寫:
func New() *LibraryStruct { ...}
在庫里不應(yīng)該存在接口的聲明,除非它被用在某個函數(shù)參數(shù)中。如果出現(xiàn)上面的 case,你就應(yīng)該想想你在寫這個庫的時候的約定。當(dāng)返回一個 interface 時,你基本上得聲明一系列可用的方法。如果有人想用這個接口來實(shí)現(xiàn)他們自己的功能(比如說為了測試),他得打亂他們的代碼來添加更多的方法。這意味著盡管在 struct 里添加方法是安全的,但在 interface 里不是。你想修改庫中的一些特性,你可以簡單的修改 struct 中一些公開的字段。但是如果你的庫只提供給用戶一個 interface,這就玩不轉(zhuǎn)了。
使用配置結(jié)構(gòu)體來避免修改你的APIs
另一種配置方法是在你的工廠函數(shù)中接收一個配置結(jié)構(gòu)體,而不是直接傳配置參數(shù)。你可以很隨意的添加新的參數(shù)而不用破壞現(xiàn)有的 API。你只需要做一件事情,在Config結(jié)構(gòu)體中添加一個新的字段,并且確保不會影響它原本的特性。
func New(config Config) *LibraryStruct { ...}
下面是一種添加結(jié)構(gòu)體字段的正確的場景,如果一個用戶初始化結(jié)構(gòu)體的時候忘了添加字段名,這是一種我認(rèn)為修改他們的代碼能得到原諒的場景。為了維護(hù)兼容性,你應(yīng)該在你的代碼中用 person{name: "Alice", age: 30} 而不是 person{"Alice", 30}。
你能在 golang.org/x/crypto[4] 包里看到對上面的補(bǔ)充。總之,對配置來說,我認(rèn)為允許用戶在返回的結(jié)構(gòu)體里設(shè)置不同的參數(shù)是一個更好的方法,并且只在編寫復(fù)雜方法時才使用這種特定方法。
感謝各位的閱讀,以上就是“如何編寫Go語言庫”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對如何編寫Go語言庫這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!