Go 由于不支持泛型而臭名昭著,但最近,泛型已接近成為現實。Go 團隊實施了一個看起來比較穩定的設計草案,并且正以源到源翻譯器原型的形式獲得關注。本文講述的是泛型的最新設計,以及如何自己嘗試泛型。
網站建設哪家好,找創新互聯!專注于網頁設計、網站建設、微信開發、微信小程序、集團企業網站建設等服務項目。為回饋新老客戶創新互聯還提供了承留免費建站歡迎大家使用!
例子
FIFO Stack
假設你要創建一個先進先出堆棧。沒有泛型,你可能會這樣實現:
type?Stack?[]interface{}func?(s?Stack)?Peek()?interface{}?{
return?s[len(s)-1]
}
func?(s?*Stack)?Pop()?{
*s?=?(*s)[:
len(*s)-1]
}
func?(s?*Stack)?Push(value?interface{})?{
*s?=?
append(*s,?value)
}
但是,這里存在一個問題:每當你 Peek 項時,都必須使用類型斷言將其從 interface{} 轉換為你需要的類型。如果你的堆棧是 *MyObject 的堆棧,則意味著很多 s.Peek().(*MyObject)這樣的代碼。這不僅讓人眼花繚亂,而且還可能引發錯誤。比如忘記 * 怎么辦?或者如果您輸入錯誤的類型怎么辦?s.Push(MyObject{})` 可以順利編譯,而且你可能不會發現到自己的錯誤,直到它影響到你的整個服務為止。
通常,使用 interface{} 是相對危險的。使用更多受限制的類型總是更安全,因為可以在編譯時而不是運行時發現問題。
泛型通過允許類型具有類型參數來解決此問題:
type?Stack(type?T)?[]Tfunc?(s?Stack(T))?Peek()?T?{
return?s[len(s)-1]
}
func?(s?*Stack(T))?Pop()?{
*s?=?(*s)[:
len(*s)-1]
}
func?(s?*Stack(T))?Push(value?T)?{
*s?=?
append(*s,?value)
}
這會向 Stack 添加一個類型參數,從而完全不需要 interface{}。現在,當你使用 Peek() 時,返回的值已經是原始類型,并且沒有機會返回錯誤的值類型。這種方式更安全,更容易使用。(譯注:就是看起來更丑陋,^-^)
此外,泛型代碼通常更易于編譯器優化,從而獲得更好的性能(以二進制大小為代價)。如果我們對上面的非泛型代碼和泛型代碼進行基準測試,我們可以看到區別:
type?MyObject?struct?{
X?
int
}
var?sink?MyObjectfunc?BenchmarkGo1(b?*testing.B)?{
for?i?:=?0;?i??b.N;?i++?{
var?s?Stack
s.Push(MyObject{})
s.Push(MyObject{})
s.Pop()
sink?=?s.Peek().(MyObject)
}
}
func?BenchmarkGo2(b?*testing.B)?{
for?i?:=?0;?i??b.N;?i++?{
var?s?Stack(MyObject)
s.Push(MyObject{})
s.Push(MyObject{})
s.Pop()
sink?=?s.Peek()
}
}
結果:
BenchmarkGo1BenchmarkGo1-16?????12837528?????????87.0?ns/op???????48?B/op????????2?allocs/opBenchmarkGo2BenchmarkGo2-16?????28406479?????????41.9?ns/op???????24?B/op????????2?allocs/op
在這種情況下,我們分配更少的內存,同時泛型的速度是非泛型的兩倍。
合約(Contracts)
上面的堆棧示例適用于任何類型。但是,在許多情況下,你需要編寫僅適用于具有某些特征的類型的代碼。例如,你可能希望堆棧要求類型實現 String() 函數
最近在做一個內網穿透工具,是用C# Dotnet Core寫的。 總擔心性能不行,想參考下別人寫的。 結果搜到很多GO語言的例子。 看了下Go語言的介紹,覺得確實是比較簡單的語言。并且在并發上比較方便。于是,就開始學習Go語言,并用Go把內網穿透工具重新寫了一下。
然后,又想用Go語言重寫之前的DotnetCore的WebAPI,現在還在編寫中,只是對比下兩個語言差異。
然后看下 C#
實際上目前我也沒有能力判斷GO和C#哪個更好
2021-11-10
列表是一種非連續的存儲容器,有多個節點組成,節點通過一些變量記錄彼此之間的關系
單鏈表和雙鏈表就是列表的兩種方法。
原理:A、B、C三個人,B懂A的電話,C懂B的電話只是單方知道號碼,這樣就形成了一個單鏈表結構。
如果C把自己的號碼給B,B把自己的號碼給A,因為是雙方都知道對方的號碼,這樣就形成了一個雙鏈表結構
如果B換號碼了,他需要通知AC,把自己的號碼刪了,這個過程就是列表的刪除操作。
在Go語言中,列表使用 container/list 包來實現,內部的實現原理是雙鏈表,列表能夠高效地進行任意位置的元素插入和刪除操作。
列表初始化的兩種辦法
列表沒有給出具體的元素類型的限制,所以列表的元素可以是任意類型的,
例如給列表中放入了一個 interface{} 類型的值,取出值后,如果要將 interface{} 轉換為其他類型將會發生宕機。
雙鏈表支持從隊列前方或后方插入元素,分別對應的方法是 PushFront 和 PushBack。
列表插入函數的返回值會提供一個 *list.Element 結構,這個結構記錄著列表元素的值以及與其他節點之間的關系等信息,從列表中刪除元素時,需要用到這個結構進行快速刪除。
遍歷完也能看到最后的結果
學習地址:
就目前來看還是很有前景,因為越來越火了,不過他的應用領域還是局限在高并發處理和網站開發,畢竟是后起之秀所以在其他桌面程序領域沒那么容易普及和超越c++,找工作就不推薦學go
? 隨著 2022 年 3 月 15 日 go 1.18 正式發布,新版本除了對性能的提升之外,還引入了很多新功能,其中就有 go 期盼已久的功能泛型(Generics),同時還引入的多模塊工作區(Workspaces)和模糊測試(Fuzzing)。
? 關于泛型網上已經有很多介紹的教程了,這里我介紹一個實用的功能,多模塊工作區的使用方法和教程。
? Go 多模塊工作區能夠使開發者能夠更容易地同時處理多個模塊的工作,如:
? 多模塊工作區
? 開發流程演示
? 總結
? 參考文獻
? go 使用的是多模塊工作區,可以讓開發者更容易同時處理多個模塊的開發。在 Go 1.17 之前,只能使用 go.mod replace 指令來實現,如果你正巧是同時進行多個模塊的開發,使用它可能是很痛苦的。每次當你想要提交代碼的時候,都不得不刪除掉 go.mod 中的 replace 才能使模塊穩定的發布版本。 ?在使用 go 1.18 多模塊工作區功能的時候,就使用這項工作變得簡單容易處理。下面我來介紹怎么使用這一功能。? Go 多模塊工作區文檔、代碼示例[5]
? 首先 我們需要 go 1.18 或更高版本 go 安裝[6]
? 通常情況下,建議不要提交 go.work 文件到 git 上,因為它主要用于本地代碼開發。
? 推薦在: $GOPATH 路徑下執行,生成 go.work 文件
? go work init 初始化工作區文件,用于生成 go.work 工作區文件
? go work use 添加新的模塊到工作區
? go work edit 用于編輯 go.work 文件
? go work sync 將工作區的構建列表同步到工作區的模塊
? go env GOWORK
? 文件結構和 go.mod 文件結構類似,支持 Go 版本號、指定工作區和需要替換的倉庫 ?文件結構示例:
? 可以使用 go work use hello 添加模塊,也可以手動修改 go.work 工作區添加新的模塊 ?在工作區中添加了模塊路徑,編譯的時候會自動使用 use 中的本地代碼進行代碼編譯,和 replaces 功能類似。
? replaces 命令與 go.mod 指令相同,用于替換項目中依賴的倉庫地址 ?需要注意的是 replaces 和 use 不能同時指定相同的本地路徑
? 錯誤示例
? 在同時使用 go.work 和 go.mod replace 功能的的時候分別指定不同的代碼倉庫路徑, go.work 優先級高于 go.mod 中定義
? 在代碼構建時候使用的是 go.work 指定的 example1 倉庫的代碼, go.work 優先級別更高
? 在 Go 1.18 go run 和 go build 都會默認使用工作區功能 ? GOWORK 也可以指定配置 go.work 文件位置
? Go 全局變量 GOWORK 設置 off 則可以禁用工作區功能
? 演示如何使用多模塊工作區功能。在現在微服務盛行的年代,一個人會維護多個代碼倉庫,很多的時候是多個倉庫進行同時開發
? 假設我們現在進行 hello 倉庫開發,實現的功能是,實現將輸入的字符串反轉并輸出,字符串反轉功能依賴于 github.com/link1st/example (下文統稱 example )公共倉庫實現
? 新建 hello 項目
? main.go 代碼
? 運行代碼 go run main.go -str "hello world" 或 go run github.com/link1st/link1st/workspaces/hello -str "hello world" 可以看到輸出了 hello world 反轉以后的字符串
? 到這里,最初的功能已經完成,但是后續需求變動,不僅需要輸出反轉以后的字符串,還需要將字符串大寫
? 我們則需要去 example 倉庫中添加開發 將字符串大寫的功能
? vim example/stringutil/to_upper.go 代碼如下
? 由于代碼還在本地調試,未提交 git 倉庫中,這個時候就需要用到 Go 多模塊工作區的功能了。
? 進入項目根目錄,初始化我們現在正在開發的模塊
? 文件結構如下
? 回到 hello 項目, vim main.go 將字符串大寫的功能添加上。
? 運行代碼
? 到這里,演示的代碼已經全部完成
? 使用 Go 多模塊工作區的功能,可以讓我們輕松在多個模塊之間切換工作,更能適應現代微服務架構開發。
[1] Go 1.18 新特性多模塊工作區教程:
[2] Go 1.18 is released!:
[3] Tutorial: Getting started with multi-module workspaces:
[4] go-1.18-features:
網站欄目:2021go語言新特性,2021csgo設置
標題URL:http://vcdvsql.cn/article30/hshdso.html
成都網站建設公司_創新互聯,為您提供標簽優化、營銷型網站建設、靜態網站、小程序開發、、網站改版
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯