How to print structure using String () fields?

This code:

type A struct { t time.Time } func main() { a := A{time.Now()} fmt.Println(a) fmt.Println(at) } 

prints:

 {{63393490800 0 0x206da0}} 2009-11-10 23:00:00 +0000 UTC 

A does not implement String() , so it is not fmt.Stringer and prints its own view. But it is very tedious to implement String() for every single structure I want to print. Even worse, I have to update String() if I add or remove some fields. Is there an easier way to print a structure with its String() s fields?

+8
string struct go
source share
1 answer

This is how the fmt package is implemented, so you cannot change it.

But you can write a helper function that uses reflect package to iterate over the fields of the structure and can call the String() method in the fields if they have such a method.

Implementation Example:

 func PrintStruct(s interface{}, names bool) string { v := reflect.ValueOf(s) t := v.Type() // To avoid panic if s is not a struct: if t.Kind() != reflect.Struct { return fmt.Sprint(s) } b := &bytes.Buffer{} b.WriteString("{") for i := 0; i < v.NumField(); i++ { if i > 0 { b.WriteString(" ") } v2 := v.Field(i) if names { b.WriteString(t.Field(i).Name) b.WriteString(":") } if v2.CanInterface() { if st, ok := v2.Interface().(fmt.Stringer); ok { b.WriteString(st.String()) continue } } fmt.Fprint(b, v2) } b.WriteString("}") return b.String() } 

Now that you want to print the struct , you can do:

 fmt.Println(PrintStruct(a, true)) 

You can also add the String() method to your structure, which just needs to call our PrintStruct() function:

 func (a A) String() string { return PrintStruct(a, true) } 

Whenever you change the structure, you do not need to do anything with your String() method, since it uses reflection to dynamically jump across all fields.

Notes:

Since we use reflection, you need to export the t time.Time field in t time.Time for this to work (several additional fields are added for testing purposes):

 type A struct { T time.Time I int unexported string } 

Testing:

 a := A{time.Now(), 2, "hi!"} fmt.Println(a) fmt.Println(PrintStruct(a, true)) fmt.Println(PrintStruct(a, false)) fmt.Println(PrintStruct("I'm not a struct", true)) 

Exit (try Go to the playground ):

 {T:2009-11-10 23:00:00 +0000 UTC I:2 unexported:hi!} {T:2009-11-10 23:00:00 +0000 UTC I:2 unexported:hi!} {2009-11-10 23:00:00 +0000 UTC 2 hi!} I'm not a struct 
+4
source share

All Articles