Go:Stringer 命令,通过代码生成提高效率
ℹ️ 本文基于Go 1.13。
stringer
命令旨在自动创建满足fmt.Stringer的方法。 它为指定类型生成String()
并将其描述为字符串。常可用于定义错误码时同时生成错误信息等场景。
案例
该命令的文档提供了一个该命令的示例。 如下:
这里是输出:
用常量的值生成日志可能会有些混乱。
让我们使用stringer -type=Pill
命令生成String()
方法:
生成了一个新的函数String()
。 这是运行先前代码时的新输出:
现在,该类型将自身描述为字符串,而不是其内部值。
stringer
也可以与生成命令完美配合,使其功能更加强大。 只需在代码中添加以下指令即可:
然后,运行go generate
命令将自动为您的所有类型生成新函数。
效率
stringer
生成一个字符串,该字符串包含作为字符串的值的列表,以及一个包含每个字符串的索引的数组。 在我们的示例中,读取Aspirin
将包括从索引7到13读取字符串:
但是它有多快和高效? 让我们与其他两种解决方案进行比较:
使用硬编码值生成
String()
函数:
这是一个包含二十个值的列表的基准:
这是具有一百个值的基准:
您拥有的常数越多,效率越高。 这实际上是有道理的。 从内存中加载值比执行一些跳转指令(表示if条件的汇编指令)要耗费更多的时间。但是,switch越大,跳转指令的数量就越大。 从某个角度来看,从内存中加载将变得更加有效。
String()
函数生成一个map:
这是一个包含二十个值的列表的基准:
使用map的速度要慢得多,因为它必须进行函数调用,并且存储桶中的查找不像访问切片索引那样简单。
自检
在生成的指令中,仅出于验证目的而创建了一些指令。 以下是这些说明:
stringer
将每行的常量名称与该值一起写入。 在此示例中,Aspirin
的值为2
。更新常量名称或其值将生成错误:
更新名称而不重新生成
String()
函数:
更新值而不重新生成
String()
函数:
但是,如果我们添加一个新的常量(这里的下一个键是数字3
)并且不更新生成的文件,则stringer
具有默认值:
添加此自检不会产生任何影响,因为在编译时将其删除。 可以通过查看程序生成的asm代码来确认:
只有String()
函数以二进制形式导出。 该检查没有性能或二进制大小的开销。
编译整理自 Go: Stringer Command, Efficiency Through Code Generation
本文首发于我的公众号:
版权声明: 本文为 InfoQ 作者【陈思敏捷】的原创文章。
原文链接:【http://xie.infoq.cn/article/e7a2d044bafbf474706e441cc】。文章转载请联系作者。
评论