How could I get an output of struct, sorted by fields?
type T struct {
B int
A int
}
t := &T{B: 2, A: 1}
doSomething(t)
fmt.Println(t) // &{1 2} --> Sorted by fields
How could I get an output of struct, sorted by fields?
type T struct {
B int
A int
}
t := &T{B: 2, A: 1}
doSomething(t)
fmt.Println(t) // &{1 2} --> Sorted by fields
A struct
is an ordered collection of fields. The fmt
package uses reflection to get the fields and values of a struct
value, and generates output in the order in which they were defined.
So the simplest solution would be to declare your type where you already have your fields arranged in alphabetical order:
type T struct {
A int
B int
}
If you can't modify the order of fields (e.g. memory layout is important), you can implement the Stringer
interface by specifying a String()
method for your struct type:
func (t T) String() string {
return fmt.Sprintf("{%d %d}", t.A, t.B)
}
The fmt
package checks if the passed value implements Stringer
, and if it does, calls its String()
method to generate the output.
Cons of this solution is that this is not flexible (e.g. if you add a new field, you have to update the String()
method too), also you have to do it for every struct
type you want it to work (and you can't define methods for types defined in other packages).
The completely flexible solution can use reflection. You can get the names of fields, sort them by name, and then iterate over the sorted names and get the field values (by name).
Pros of this solution is that this works for any struct
, and it keeps working without modification even if you add or remove fields from your structs. It also works for fields of any type, not just for int
fields.
Here is an example how to do it (try it on the Go Playground):
func printFields(st interface{}) string {
t := reflect.TypeOf(st)
names := make([]string, t.NumField())
for i := range names {
names[i] = t.Field(i).Name
}
sort.Strings(names)
v := reflect.ValueOf(st)
buf := &bytes.Buffer{}
buf.WriteString("{")
for i, name := range names {
val := v.FieldByName(name)
if !val.CanInterface() {
continue
}
if i > 0 {
buf.WriteString(" ")
}
fmt.Fprintf(buf, "%v", val.Interface())
}
buf.WriteString("}")
return buf.String()
}
Make T
implement the Stringer interface (see package fmt) and do either print A orb B first.
BTW. This is a stupid idea.