Go具有強大的靜態類型,並且不支持泛型,那麼我們如何定義可應用於多個類型的通用數據結構和算法?interface{}
s不是解決方案,因為它們需要強制轉換,而我們失去了擁有強大的靜態類型的許多優點。解決方案是代碼生成,因為它允許進行編譯時檢查和安全性以及更高的性能。
在搜索代碼生成主題時,我發現這些信息不容易獲得,但是我偶然發現了更複雜的用例和場景,因此這裡用簡單的英語進行了解釋。
問題:
我想要實現數據結構(同樣適用於算法)以最一般的方式使用Go,並且生成特定於類型的實現,我可以輕鬆地重用。
解決方案:
使用金妮,這再簡單不過了:
- 進口
genny/generic
- 將一種或多種類型定義為
generic.Type
,例如打電話給他們Item
或者Type
- 在代碼中使用這些類型
- 跑
genny
生成特定於類型的實現
例子
看看這個簡單的例子,它是在Go中設置數據結構實現:
// Package set creates a ItemSet data structure for the Item type
package set
import “github.com/cheekybits/genny/generic”
// Item the type of the Set
type Item generic.Type
// ItemSet the set of Items
type ItemSet struct {
items map[Item]bool
}
// Add adds a new element to the Set. Returns the Set.
func (s ItemSet) Add(t Item) ItemSet {
if s.items == nil {
s.items = make(map[Item]bool)
}
_, ok := s.items[t]
if !ok {
s.items[t] = true
}
return s
}
// Clear removes all elements from the Set
func (s ItemSet) Clear() {
(s).items = make(map[Item]bool)
}
通過運行
genny -in set.go -out gen-set.go gen "Item=string,int"
現在在命令行中,如果該文件被調用set.go
它將產生一個gen-set.go
其中包含以下內容:
// This file was automatically generated by genny.
// Any changes will be lost if this file is regenerated.
// see https://github.com/cheekybits/genny
// Package Set creates a StringSet data structure for the string type
package set
// StringSet the set of Strings
type StringSet struct {
items map[string]bool
}
// Add adds a new element to the Set. Returns the Set.
func (s StringSet) Add(t string) StringSet {
s.items[t] = true
return s
}
// Clear removes all elements from the Set
func (s StringSet) Clear() {
(s).items = make(map[string]bool)
}
// Delete removes the string from the Set and returns Has(string)
func (s StringSet) Delete(item string) bool {
ret := (s).Has(item)
if ret {
delete((*s).items, item)
}
return ret
}
// Has returns true if the Set contains the string
func (s StringSet) Has(item string) bool {
return (s).items[item]
}
// Strings returns the string(s) stored
func (s *StringSet) Strings() []string {
items := []string{}
for i := range s.items {
items = append(items, i)
}
return items
}
// Package Set creates a IntSet data structure for the int type
// IntSet the set of Ints
type IntSet struct {
items map[int]bool
}
// Add adds a new element to the Set. Returns the Set.
func (s IntSet) Add(t int) IntSet {
s.items[t] = true
return s
}
// Clear removes all elements from the Set
func (s IntSet) Clear() {
(s).items = make(map[int]bool)
}
// Delete removes the int from the Set and returns Has(int)
func (s IntSet) Delete(item int) bool {
ret := (s).Has(item)
if ret {
delete((*s).items, item)
}
return ret
}
// Has returns true if the Set contains the int
func (s IntSet) Has(item int) bool {
return (s).items[item]
}
// Ints returns the int(s) stored
func (s *IntSet) Ints() []int {
items := []int{}
for i := range s.items {
items = append(items, i)
}
return items
}
如你看到的,genny
創建了StringSet
和IntSet
來自的結構ItemSet
**,因為告訴了它Item=string,int
。
它還創建了struct方法構成我們的Set實現。
如果我們想向我們的應用程序添加另一組類型,我們可以編輯命令並再次運行它。
使用go generate
您也可以通過在文件頂部,包doc下方添加註釋來自動執行此操作,例如:
// go:generate genny -in=$GOFILE -out=gen-$GOFILE gen "Item=string,int"
這說明go generate
,通過genny
,以生成版本翻譯Item
到string
,以及第二個版本的翻譯item
到int
。
跑
go generate
得到gen-set.go
文件,帶有字符串和整數集。
測驗
重要提示:以上數據結構的通用實現編譯並可以測試就像由...生成的具體實現一樣容易go generate
,因此我們可以針對通用實現以及特定於類型的測試進行測試。
更多教程:
- 使用NGINX反向代理服務Go服務
- 在Go中復制結構
- Go Web服務器的基礎
- 在Go中對地圖類型進行排序
- 簡而言之去指針
- 轉到標籤說明
- 開始日期和時間格式
- 使用Go進行JSON處理
- 可變參數函數
- 去弦備忘單
- 轉到空界面說明
- 使用VS Code和Delve調試Go
- 命名為Go返回參數
- 在Go中生成隨機數和字符串
- Go項目的文件系統結構
- Go中的二進制搜索算法
- 在Go中使用命令行標誌
- GOPATH解釋
- 使用Go構建一個命令行應用程序:lolcat
- 使用Go構建CLI命令:Cowsay
- 在Go中使用殼管
- Go CLI教程:財富克隆
- 使用Go列出文件夾中的文件
- 使用Go從GitHub獲取存儲庫列表
- 去,將一小段字符串附加到文件中
- 去,將字符串轉換為字節片
- 使用Go可視化您本地的Git貢獻
- Go CPU和內存分析入門
- 解決Go程序中的“不支持索引”錯誤
- 測量Go程序中的執行時間
- 使用Go構建Web爬網程序以檢測重複的標題
- 最佳實踐:指針還是價值接收者?
- 最佳實踐:您應該使用方法還是函數?
- Go數據結構:集
- 前往地圖備忘單
- 在Go中生成泛型類型的實現
- Go數據結構:字典
- Go數據結構:哈希表
- 在“通過通道”中實現事件偵聽器
- Go數據結構:堆棧
- Go數據結構:隊列
- Go數據結構:二進制搜索樹
- Go數據結構:圖形
- Go數據結構:鍊錶
- Go數據結構的完整指南
- 比較Go值
- Go是面向對象的嗎?
- 在Go中使用SQL數據庫
- 在Go中使用環境變量
- 上篇教程:PostgreSQL支持的REST API
- 在Go Web服務器上啟用CORS
- 在Docker容器中部署Go應用程序
- 為什麼Go是作為PHP開發人員學習的功能強大的語言
- 去,刪除io.Reader.ReadString換行符
- 開始,如何觀看更改並重建程序
- 去算一下自約會以來的月份
- 在Go中訪問HTTP POST參數