stringer的使用

更多好文请关注v
golang技术实验室

作用

stringer命令旨在自动创建满足fmt.Stringer的方法。它为指定类型生成String()并将其描述为字符串。常可用于定义错误码时同时生成错误信息等场景。

平时开发中我们都会有映射的需求,一般我们这么做

package main

import "fmt"

const (
	One = iota
	Two
	Three
)

//key 和value的映射
var Mp = map[int]string{
	One: "one",
	Two: "two",
	Three: "three",
}

func main(){
	var is int
	is = 1
	if is == Two{
		fmt.Println(Mp[Two])
	}

}

输出

-> % go run main.go        
two

2、stringer

安装

go get golang.org/x/tools/cmd/stringer

生成映射文件

stringer -type=IntModel

-rw-r--r--  1 zhangsan  staff   624B Jun 17 13:41 intmodel_string.go
-rw-r--r--  1 zhangsan  staff    92B Jun 17 13:41 main.go

stringer也可以与生成命令完美配合,使其功能更加强大。只需在代码中添加以下指令即可:

//go:generate stringer -type=IntModel

然后,运行go generate命令将自动为您的所有类型生成新函数。

Flags:
  -linecomment
        use line comment text as printed text when present
  -output string
        output file name; default srcdir/<type>_string.go
  -tags string
        comma-separated list of build tags to apply
  -trimprefix prefix
        trim the prefix from the generated constant names
  -type string
        comma-separated list of type names; must be set

可以指定文件名

我们来看下内容

// Code generated by "stringer -type=IntModel"; DO NOT EDIT.

package main

import "strconv"

func _() {
	// An "invalid array index" compiler error signifies that the constant values have changed.
	// Re-run the stringer command to generate them again.
	var x [1]struct{}
	_ = x[One-0]
	_ = x[Two-1]
	_ = x[Three-2]
}

const _IntModel_name = "OneTwoThree"

var _IntModel_index = [...]uint8{0, 3, 6, 11}

func (i IntModel) String() string {
	if i < 0 || i >= IntModel(len(_IntModel_index)-1) {
		return "IntModel(" + strconv.FormatInt(int64(i), 10) + ")"
	}
	return _IntModel_name[_IntModel_index[i]:_IntModel_index[i+1]]
}

在这里插入图片描述

3、验证

package main

import (
	"fmt"
	"strconv"
)

type IntModel int

const (
	One IntModel = iota
	Two
	Three
)


func main(){
	p := Two
	var is int
	is = 1
	if p == IntModel(is){
		fmt.Println(p)
	}
}

func _() {
	// An "invalid array index" compiler error signifies that the constant values have changed.
	// Re-run the stringer command to generate them again.
	var x [1]struct{}
	_ = x[One-0]
	_ = x[Two-1]
	_ = x[Three-2]
}

const _IntModel_name = "OneTwoThree"

var _IntModel_index = [...]uint8{0, 3, 6, 11}

func (i IntModel) String() string {
	if i < 0 || i >= IntModel(len(_IntModel_index)-1) {
		return "IntModel(" + strconv.FormatInt(int64(i), 10) + ")"
	}
	return _IntModel_name[_IntModel_index[i]:_IntModel_index[i+1]]
}
-> % go run main.go
Two

在string包中,只要实现了String,fmt.println()就会自动调用String,fmt.Printf也会

4、对比

func Switch(i int )string{
	switch i {
	case 0:
		return "one"
	case 1:
		return "two"
	case 2:
		return "three"
	default:
		return ""
	}
}

或者if分操作对比发现

这是一个包含二十个值的列表的基准:

name                  time/op
Stringer-4            4.16ns ± 2%
StringerWithSwitch-4  3.81ns ± 1%

这是具有一百个值的基准:

name                  time/op
Stringer-4            4.96ns ± 0%
StringerWithSwitch-4  4.99ns ± 1%

拥有的常数越多,效率越高。这实际上是有道理的。从内存中加载值比执行一些跳转指令(表示if条件的汇编指令)要耗费更多的时间。但是,switch越大,跳转指令的数量就越大。从某个角度来看,从内存中加载将变得更加有效。

自检

在生成的指令中,仅出于验证目的而创建了一些指令。以下是这些说明:

在这里插入图片描述

stringer将每行的常量名称与该值一起写入。在此示例中,Aspirin的值为2。更新常量名称或其值将生成错误:

  • 更新名称而不重新生成String()函数:

  • 更新值而不重新生成String()函数:

# command-line-arguments
./main.go:30:7: invalid array index One - 0 (out of bounds for 1-element array)
./main.go:31:7: invalid array index Two - 1 (out of bounds for 1-element array)
./main.go:32:7: invalid array index Three - 2 (out of bounds for 1-element array)

但是,如果我们添加一个新的常量(这里的下一个键是数字3)并且不更新生成的文件,则stringer具有默认值:

IntModel(3)

添加此自检不会产生任何影响,因为在编译时将其删除。可以通过查看程序生成的asm代码来确认:

➜  go tool compile -S main.go pill_string.go | grep "\"\".IntModel\.[^\s]* STEXT"
"".Pill.String STEXT size=275 args=0x18 locals=0x50

只有String()函数以二进制形式导出。该检查没有性能或二进制大小的开销。

更多好文请关注v
golang技术实验室

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

a...Z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值