1 // Copyright 2017, The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE.md file.
5 // Package value provides functionality for reflect.Value types.
16 var stringerIface = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
18 // Format formats the value v as a string.
20 // This is similar to fmt.Sprintf("%+v", v) except this:
21 // * Prints the type unless it can be elided
22 // * Avoids printing struct fields that are zero
23 // * Prints a nil-slice as being nil, not empty
24 // * Prints map entries in deterministic order
25 func Format(v reflect.Value, conf FormatConfig) string {
27 conf.followPointers = true
28 conf.realPointers = true
29 return formatAny(v, conf, nil)
32 type FormatConfig struct {
33 UseStringer bool // Should the String method be used if available?
34 printType bool // Should we print the type before the value?
35 PrintPrimitiveType bool // Should we print the type of primitives?
36 followPointers bool // Should we recursively follow pointers?
37 realPointers bool // Should we print the real address of pointers?
40 func formatAny(v reflect.Value, conf FormatConfig, visited map[uintptr]bool) string {
41 // TODO: Should this be a multi-line printout in certain situations?
44 return "<non-existent>"
46 if conf.UseStringer && v.Type().Implements(stringerIface) && v.CanInterface() {
47 if (v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface) && v.IsNil() {
51 const stringerPrefix = "s" // Indicates that the String method was used
52 s := v.Interface().(fmt.Stringer).String()
53 return stringerPrefix + formatString(s)
58 return formatPrimitive(v.Type(), v.Bool(), conf)
59 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
60 return formatPrimitive(v.Type(), v.Int(), conf)
61 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
62 if v.Type().PkgPath() == "" || v.Kind() == reflect.Uintptr {
63 // Unnamed uints are usually bytes or words, so use hexadecimal.
64 return formatPrimitive(v.Type(), formatHex(v.Uint()), conf)
66 return formatPrimitive(v.Type(), v.Uint(), conf)
67 case reflect.Float32, reflect.Float64:
68 return formatPrimitive(v.Type(), v.Float(), conf)
69 case reflect.Complex64, reflect.Complex128:
70 return formatPrimitive(v.Type(), v.Complex(), conf)
72 return formatPrimitive(v.Type(), formatString(v.String()), conf)
73 case reflect.UnsafePointer, reflect.Chan, reflect.Func:
74 return formatPointer(v, conf)
78 return fmt.Sprintf("(%v)(nil)", v.Type())
82 if visited[v.Pointer()] || !conf.followPointers {
83 return formatPointer(v, conf)
85 visited = insertPointer(visited, v.Pointer())
86 return "&" + formatAny(v.Elem(), conf, visited)
87 case reflect.Interface:
90 return fmt.Sprintf("%v(nil)", v.Type())
94 return formatAny(v.Elem(), conf, visited)
98 return fmt.Sprintf("%v(nil)", v.Type())
102 if visited[v.Pointer()] {
103 return formatPointer(v, conf)
105 visited = insertPointer(visited, v.Pointer())
110 subConf.printType = v.Type().Elem().Kind() == reflect.Interface
111 for i := 0; i < v.Len(); i++ {
112 s := formatAny(v.Index(i), subConf, visited)
115 s := fmt.Sprintf("{%s}", strings.Join(ss, ", "))
117 return v.Type().String() + s
123 return fmt.Sprintf("%v(nil)", v.Type())
127 if visited[v.Pointer()] {
128 return formatPointer(v, conf)
130 visited = insertPointer(visited, v.Pointer())
133 keyConf, valConf := conf, conf
134 keyConf.printType = v.Type().Key().Kind() == reflect.Interface
135 keyConf.followPointers = false
136 valConf.printType = v.Type().Elem().Kind() == reflect.Interface
137 for _, k := range SortKeys(v.MapKeys()) {
138 sk := formatAny(k, keyConf, visited)
139 sv := formatAny(v.MapIndex(k), valConf, visited)
140 ss = append(ss, fmt.Sprintf("%s: %s", sk, sv))
142 s := fmt.Sprintf("{%s}", strings.Join(ss, ", "))
144 return v.Type().String() + s
150 subConf.printType = true
151 for i := 0; i < v.NumField(); i++ {
154 continue // Elide zero value fields
156 name := v.Type().Field(i).Name
157 subConf.UseStringer = conf.UseStringer
158 s := formatAny(vv, subConf, visited)
159 ss = append(ss, fmt.Sprintf("%s: %s", name, s))
161 s := fmt.Sprintf("{%s}", strings.Join(ss, ", "))
163 return v.Type().String() + s
167 panic(fmt.Sprintf("%v kind not handled", v.Kind()))
171 func formatString(s string) string {
172 // Use quoted string if it the same length as a raw string literal.
173 // Otherwise, attempt to use the raw string form.
174 qs := strconv.Quote(s)
175 if len(qs) == 1+len(s)+1 {
179 // Disallow newlines to ensure output is a single line.
180 // Only allow printable runes for readability purposes.
181 rawInvalid := func(r rune) bool {
182 return r == '`' || r == '\n' || !unicode.IsPrint(r)
184 if strings.IndexFunc(s, rawInvalid) < 0 {
190 func formatPrimitive(t reflect.Type, v interface{}, conf FormatConfig) string {
191 if conf.printType && (conf.PrintPrimitiveType || t.PkgPath() != "") {
192 return fmt.Sprintf("%v(%v)", t, v)
194 return fmt.Sprintf("%v", v)
197 func formatPointer(v reflect.Value, conf FormatConfig) string {
199 if !conf.realPointers {
200 p = 0 // For deterministic printing purposes
202 s := formatHex(uint64(p))
204 return fmt.Sprintf("(%v)(%s)", v.Type(), s)
209 func formatHex(u uint64) string {
218 case u <= 0xffffffff:
220 case u <= 0xffffffffff:
222 case u <= 0xffffffffffff:
224 case u <= 0xffffffffffffff:
226 case u <= 0xffffffffffffffff:
229 return fmt.Sprintf(f, u)
232 // insertPointer insert p into m, allocating m if necessary.
233 func insertPointer(m map[uintptr]bool, p uintptr) map[uintptr]bool {
235 m = make(map[uintptr]bool)
241 // isZero reports whether v is the zero value.
242 // This does not rely on Interface and so can be used on unexported fields.
243 func isZero(v reflect.Value) bool {
246 return v.Bool() == false
247 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
249 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
251 case reflect.Float32, reflect.Float64:
252 return v.Float() == 0
253 case reflect.Complex64, reflect.Complex128:
254 return v.Complex() == 0
256 return v.String() == ""
257 case reflect.UnsafePointer:
258 return v.Pointer() == 0
259 case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
262 for i := 0; i < v.Len(); i++ {
263 if !isZero(v.Index(i)) {
269 for i := 0; i < v.NumField(); i++ {
270 if !isZero(v.Field(i)) {