Stringer is a tool to automate the creation of methods that satisfy the fmt.Stringer interface. Given the name of a (signed or unsigned) integer type T that has constants defined, stringer will create a new self-contained Go source file implementing:
func (t T) String() string
The file is created in the same package and directory as the package that defines T. It has helpful defaults designed for use with go generate.
Stringer is among other Golang tools which help us in writing good go code. This is a CLI tool which is used via
go generate. Go generate is another tool that comes with go. It is used for auto-generating code. You can explore more about it here.
So, we use the stringer command with go generate to generate the code necessary to implement fmt’s stringer interface. Conceptually this is very simple. But the documentation for stringer is, well there is no documentation. There is only a help flag in the stringer command which only lists the available flags we can use with stringer. These flags are very useful but are ignored by many people. They give us control over how the final output string is formatted.
What stringer is used for
Stringer is generally used to implement the concept of enumeration while avoiding hard-coding of the string values. Enumeration or enum is when you want to define a finite and fixed set of values of a given type. For example, types of dishes in a menu (appetizers, main course, desserts), types of pokemon (grass, water, fire, ..), etc.
So, when we want to use these defined sets of values, we should avoid hard coding them as it can lead to human errors like spelling mistakes. If we use something like stringer, we will generate the values once and make sure there are no errors. After that, we can just use them without worrying about human errors.
The types that we define as enums will be extending
int . So, when we declare the variables for each element, they will hold int values (value1 = 1, value2 = 2, etc). These
int values will be used by stringer internally to index the values. But, we don’t have to manually initialise the
int value for each of the elements. Go provides an identifier called
iota to incrementally initialise
int values. Let’s look at an example for
Let's go over each of the flags stringer has and see how they can be used with some examples.
-type is a compulsory argument which defines which type the string belongs to. This argument also supports a list of comma-separated type names. The
String() method will be generated for all the given types. But this method’s definition will be put in a separate file. This file will by default be named
<type>_string.go . Let’s look at an example for the
String() definitions will be put in a single file called
herotype_string.go . If we want them to be in separate files, we will need to have two
go generate comments like this:
//go:generate stringer -type=HeroType
//go:generate stringer -type=AttackType
This will create two files:
attacktype_string.go . To generate these files, we need to run the command
go generate in the same directory. This will create the files. And every time we run
go generate , these files will be regenerated. So, it is important that we do not edit these generated files manually as they will get overwritten.
-output flag is used to explicitly specify the name of the file what will be generated. This will override the default name
<type>_string.go . That’s pretty much all this flag does. So, for the above example, if we wanted to put both the type’s generations into a single file called
hero-attack_string.go , we can use the
-output flag like this:
//go:generate stringer -type=HeroType,AttackType -output=hero-attack_string.go
This will generate the single
hero-attack_string.go with both the
Sometimes, we would want to name the enum variables descriptively with a prefix, to make the code more readable (Ex:
HeroTypeAgility instead of just
Agility ). But this exact name would get reflected in the final output string. We can use the
-trimprefix to avoid this and trim the prefix before generating the final string output. This will trim the specified prefix and only use the rest of the text as the value.
This will generate the
String() function which return the above values with “HeroType” trimmed off: “Strength”, “Agility”, “Intelligence”
This flag, like
trimprefix is also used for customising what the
String() function returns.
trimprefix only lets you trim of the prefix of the value, but this flag lets you set WHATEVER value you want to a particular object of that type. This custom value is set by adding a comment on the same line as the object, with the value you want to set. Example:
This will generate enums with the values: “led-zeppelin”, “pink-floyd” and “post-malone”. This way, we can have “-” in the string value.
linecomment is generally used in cases like this when we want to have special characters, start the value with a lower case, keep the variable camel-case and the values snake-case etc.
NOTE: The comment has to be on the same line. And the space after
This flag is used to specify the build tags. These build tags are used for conditionally generate the
String() function. I am not very sure about how to specifically use this. I tried to find out, but couldn’t find much online. If you know any examples, please comment below.
These are the flags available in
stringer . This is a fairly simple tool to use. Hope this post give you more clarity about it.