How to sort struct fields in alphabetical order

ぃ、小莉子 提交于 2019-12-31 03:04:20

问题


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

回答1:


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()
}



回答2:


Make T implement the Stringer interface (see package fmt) and do either print A orb B first.

BTW. This is a stupid idea.



来源:https://stackoverflow.com/questions/30913483/how-to-sort-struct-fields-in-alphabetical-order

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!