Skip to main content
 首页 » 编程设计

生成模板代码实现Golang泛型

2022年07月19日130落叶无声

生成模板代码实现Golang泛型

Golang是强类型静态语言,暂不支持泛型。那么如何定义通用类型的数据结构和算法呢?使用interface{}不是好的解决方案,接口需要转换同时会丢失静态类型的优势。本文我们介绍模板代码结合代码生成器,实现编译时检查、安全的、高性能的泛型编程。

1. 实现通用Set数据结构

如何实现一个数据结构(算法也一样)支持常用类型,生成特定类型实现,可以轻松重用。

使用genny,非常简单几个步骤:

  1. 导入genny/generic
  2. 定义类型为通用类型generic.Type,例如,命令为ItemType
  3. 在代码中使用这些通用类型
  4. 运行genny生成类型实现

下面实现比较简单的Set数据结构,定义ItemSet泛型Set,同时定义了Add和Clean方法:

//go:generate genny -in=$GOFILE -out=gen-$GOFILE gen "Item=string,int" 
 
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 
} 
 
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 
} 
 
func (s *ItemSet) Clean(){ 
	s.items = make(map[Item]bool) 
} 
 

当然需要先使用go get -u github.com/cheekybits/genny 命令安装genny,编译通过后。运行命令:
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帮我们从ItemSet **生成了StringSetIntSet结构,因为Item=string,int

同时也生成对应结构体方法,如果你想增加其他类型,只要编辑命令重新运行。

2. 使用 go generate

我们也可以通过在文件的顶部,包文档注释的下面增加go generate注释:

//go:generate genny -in=$GOFILE -out=gen-$GOFILE gen "Item=string,int"

命令指定使用genny,同时需要翻译Item为string和int。接着直接在源文件目录下运行下面命令:

go generate 

同样会生成gen-set.go文件,包括string和int类型结构体。

重要:上面通用实现的数据结构可以像go generate生成的具体实现一样,进行编译和测试,因此可以针对通用或特定类型的实现运行测试。

3. 总结

本文介绍了利用gennygo generate生成代码,辅助实现泛型数据结构和算法。


本文参考链接:https://blog.csdn.net/neweastsun/article/details/107165041
阅读延展