How to make Go print enum fields as string?

43,049

Solution 1

You need to make the field exported,ie you may declare the struct as

type MyStruct struct {
    Field MyEnum
}

Here is a sample program with exported and unexported fields

Code

package main

import (
    "fmt"
)

type MyEnum int

const (
    Foo MyEnum = 1
    Bar MyEnum = 2
)

func (e MyEnum) String() string {
    switch e {
    case Foo:
        return "Foo"
    case Bar:
        return "Bar"
    default:
        return fmt.Sprintf("%d", int(e))
    }
}

type MyStruct struct {
    Field1 MyEnum
    field2 MyEnum
}

func main() {
    info := &MyStruct{
        Field1: MyEnum(1),
        field2: MyEnum(2),
    }
    fmt.Printf("%v\n", MyEnum(1))
    fmt.Printf("%v\n", info)
    fmt.Printf("%+v\n", info)
    fmt.Printf("%#v\n", info)
}

Output

Foo
&{Foo 2}
&{Field1:Foo field2:2}
&main.MyStruct{Field1:1, field2:2}

Here is play link : https://play.golang.org/p/7knxM4KbLh

Solution 2

I am going to expand on the accepted answer a little with this method:

type MyEnum int

const (
    Foo MyEnum = iota
    Bar
)

func (me MyEnum) String() string {
    return [...]string{"Foo", "Bar"}[me]
}

// ...

fmt.Println(Foo, Bar)  // Prints: Foo Bar

The above code assumes that the enum values starts from 0, which works out nicely because the first element in the array in the method String can be referenced by the enum value directly.

But the first enum value in the original question has a value of 1. We can modify it the method accordingly.

const (
    Foo MyEnum = iota + 1
    Bar
)

func (me MyEnum) String() string {
    return [...]string{"", "Foo", "Bar"}[me]
}

Here's the playlink: https://play.golang.org/p/6pmyVlsAeV2

Solution 3

Use stringer. It is an integral part of the Golang tool chain and is made specifically for this task.

Share:
43,049

Related videos on Youtube

Igor Gatis
Author by

Igor Gatis

Updated on July 14, 2021

Comments

  • Igor Gatis
    Igor Gatis almost 3 years

    You print an enum that implements Stringer using "%v", it will print its string value. If you declare the same enum inside a struct and print the struct using "%v", it will print enum's numeric value. Is there a way to print the string value of a enum field?

    Sample (https://play.golang.org/p/AP_tzzAZMI):

    package main
    
    import (
        "fmt"
    )
    
    type MyEnum int
    
    const (
        Foo MyEnum = 1
        Bar MyEnum = 2
    )
    
    func (e MyEnum) String() string {
        switch e {
        case Foo:
            return "Foo"
        case Bar:
            return "Bar"
        default:
            return fmt.Sprintf("%d", int(e))
        }
    }
    
    type MyStruct struct {
        field MyEnum
    }
    
    func main() {
        info := &MyStruct{
            field: MyEnum(1),
        }
        fmt.Printf("%v\n", MyEnum(1))
        fmt.Printf("%v\n", info)
        fmt.Printf("%+v\n", info)
        fmt.Printf("%#v\n", info)
    }
    

    Prints:

    Foo
    &{1}
    &{field:1}
    &main.MyStruct{field:1}
    
    • GarMan
      GarMan over 7 years
      This is a dup of stackoverflow.com/questions/27187132/… , there is no way to get the name of the enum in go, you need to create a lut with a tool like stringify
    • icza
      icza over 7 years
      @GarMan The question is not about how to write or generate the String() method, it's about he already added the String(), yet the fmt package doesn't call it when an instance of a wrapper struct (or a pointer to it) is printed.
    • Sarath Sadasivan Pillai
      Sarath Sadasivan Pillai over 7 years
      @Gatis you need to export the field. I have added the answer with a sample.Please check and if it solves your problem accept it
    • GarMan
      GarMan over 7 years
      My bad, I misread, @Sarathsp's answer is correct please accept it.
  • Sarath Sadasivan Pillai
    Sarath Sadasivan Pillai over 7 years
    if you want '%#v' also to show the string you need to implement 'fmt.GoStringer'
  • giles
    giles about 3 years
    Can you explain the ellipsis used here? [...] string { "a", "b", "c" } [n] appears to give me the same result as without the ellipsis [] string { "a", "b", "c" } [n] So I am not sure what purpose the ellipsis is serving.
  • Cybersam
    Cybersam about 3 years
    Yes. Both [...] string { "a", "b", "c" } [n] and [] string { "a", "b", "c" } [n] give the same result. The difference is the former creates an array and the latter a slice. This declares a slice: a := string { "a", "b", "c" }. This declares an array of 2: b := [3]string{ "a", "b", "c" }. This is the same as the previous except you let Go compiler to do the counting of elements for you: b := [...]string{ "a", "b", "c" } . Reference: blog.golang.org/slices-intro
  • Rishabh Bhatnagar
    Rishabh Bhatnagar about 3 years
    This way, you'll be creating a slice on every call to the function. Either define this mapping as a global object or use a switch. Else, the memory's gonna blow if there are a large number of threads trying to use the enum object's string.