如何获得按字段排序的struct输出?
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是字段的 有序 集合。该fmt包使用反射来获取值的字段和值struct,并按照定义它们的顺序生成输出。
struct
fmt
因此,最简单的解决方案是在已经按字母顺序排列字段的位置声明类型:
type T struct { A int B int }
如果您不能修改字段的顺序(例如,内存布局很重要),则可以Stringer通过String()为结构类型指定一个方法来实现接口:
Stringer
String()
func (t T) String() string { return fmt.Sprintf("{%d %d}", t.A, t.B) }
所述fmt包检查所传递的值工具Stringer,并且如果是的话,调用它的String()方法,以产生输出。
该解决方案的缺点是这种方法不灵活(例如,如果添加新字段,也必须更新String()方法),还必须针对struct希望其工作的每种类型执行此操作(并且无法定义方法)用于其他包中定义的类型)。
完全灵活的解决方案可以使用反射。您可以获取字段名称,按名称对其进行排序,然后遍历排序后的名称并获取字段值(按名称)。
该解决方案的优点是,它适用于任何struct,即使您在结构中添加或删除字段,它也无需修改即可正常工作。它也适用于任何类型的字段,而不仅仅是int字段。
int
这是一个示例(在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() }