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参数