mirror of
https://github.com/golang/go.git
synced 2025-05-25 17:31:22 +00:00
fmt: print &map like &slice and &struct
It was inconsistent. Also test these better. Also document the default format for types. This wasn't written down. Fixes #8470. LGTM=iant R=golang-codereviews, iant CC=golang-codereviews https://golang.org/cl/154870043
This commit is contained in:
parent
668ea79283
commit
a0c5adc35c
@ -13,7 +13,7 @@
|
|||||||
The verbs:
|
The verbs:
|
||||||
|
|
||||||
General:
|
General:
|
||||||
%v the value in a default format.
|
%v the value in a default format
|
||||||
when printing structs, the plus flag (%+v) adds field names
|
when printing structs, the plus flag (%+v) adds field names
|
||||||
%#v a Go-syntax representation of the value
|
%#v a Go-syntax representation of the value
|
||||||
%T a Go-syntax representation of the type of the value
|
%T a Go-syntax representation of the type of the value
|
||||||
@ -51,6 +51,21 @@
|
|||||||
There is no 'u' flag. Integers are printed unsigned if they have unsigned type.
|
There is no 'u' flag. Integers are printed unsigned if they have unsigned type.
|
||||||
Similarly, there is no need to specify the size of the operand (int8, int64).
|
Similarly, there is no need to specify the size of the operand (int8, int64).
|
||||||
|
|
||||||
|
The default format for %v is:
|
||||||
|
bool: %t
|
||||||
|
int, int8 etc.: %d
|
||||||
|
uint, uint8 etc.: %d, %x if printed with %#v
|
||||||
|
float32, complex64, etc: %g
|
||||||
|
string: %s
|
||||||
|
chan: %p
|
||||||
|
pointer: %p
|
||||||
|
For compound objects, the elements are printed using these rules, recursively,
|
||||||
|
laid out like this:
|
||||||
|
struct: {field0 field1 ...}
|
||||||
|
array, slice: [elem0 elem1 ...]
|
||||||
|
maps: map[key1:value1 key2:value2]
|
||||||
|
pointer to above: &{}, &[], &map[]
|
||||||
|
|
||||||
Width is specified by an optional decimal number immediately following the verb.
|
Width is specified by an optional decimal number immediately following the verb.
|
||||||
If absent, the width is whatever is necessary to represent the value.
|
If absent, the width is whatever is necessary to represent the value.
|
||||||
Precision is specified after the (optional) width by a period followed by a
|
Precision is specified after the (optional) width by a period followed by a
|
||||||
|
@ -965,11 +965,12 @@ func TestFlagParser(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestStructPrinter(t *testing.T) {
|
func TestStructPrinter(t *testing.T) {
|
||||||
var s struct {
|
type T struct {
|
||||||
a string
|
a string
|
||||||
b string
|
b string
|
||||||
c int
|
c int
|
||||||
}
|
}
|
||||||
|
var s T
|
||||||
s.a = "abc"
|
s.a = "abc"
|
||||||
s.b = "def"
|
s.b = "def"
|
||||||
s.c = 123
|
s.c = 123
|
||||||
@ -979,12 +980,35 @@ func TestStructPrinter(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{"%v", "{abc def 123}"},
|
{"%v", "{abc def 123}"},
|
||||||
{"%+v", "{a:abc b:def c:123}"},
|
{"%+v", "{a:abc b:def c:123}"},
|
||||||
|
{"%#v", `fmt_test.T{a:"abc", b:"def", c:123}`},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
out := Sprintf(tt.fmt, s)
|
out := Sprintf(tt.fmt, s)
|
||||||
if out != tt.out {
|
if out != tt.out {
|
||||||
t.Errorf("Sprintf(%q, &s) = %q, want %q", tt.fmt, out, tt.out)
|
t.Errorf("Sprintf(%q, s) = %#q, want %#q", tt.fmt, out, tt.out)
|
||||||
}
|
}
|
||||||
|
// The same but with a pointer.
|
||||||
|
out = Sprintf(tt.fmt, &s)
|
||||||
|
if out != "&"+tt.out {
|
||||||
|
t.Errorf("Sprintf(%q, &s) = %#q, want %#q", tt.fmt, out, "&"+tt.out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSlicePrinter(t *testing.T) {
|
||||||
|
slice := []int{}
|
||||||
|
s := Sprint(slice)
|
||||||
|
if s != "[]" {
|
||||||
|
t.Errorf("empty slice printed as %q not %q", s, "[]")
|
||||||
|
}
|
||||||
|
slice = []int{1, 2, 3}
|
||||||
|
s = Sprint(slice)
|
||||||
|
if s != "[1 2 3]" {
|
||||||
|
t.Errorf("slice: got %q expected %q", s, "[1 2 3]")
|
||||||
|
}
|
||||||
|
s = Sprint(&slice)
|
||||||
|
if s != "&[1 2 3]" {
|
||||||
|
t.Errorf("&slice: got %q expected %q", s, "&[1 2 3]")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1014,6 +1038,12 @@ func TestMapPrinter(t *testing.T) {
|
|||||||
a := []string{"1:one", "2:two", "3:three"}
|
a := []string{"1:one", "2:two", "3:three"}
|
||||||
presentInMap(Sprintf("%v", m1), a, t)
|
presentInMap(Sprintf("%v", m1), a, t)
|
||||||
presentInMap(Sprint(m1), a, t)
|
presentInMap(Sprint(m1), a, t)
|
||||||
|
// Pointer to map prints the same but with initial &.
|
||||||
|
if !strings.HasPrefix(Sprint(&m1), "&") {
|
||||||
|
t.Errorf("no initial & for address of map")
|
||||||
|
}
|
||||||
|
presentInMap(Sprintf("%v", &m1), a, t)
|
||||||
|
presentInMap(Sprint(&m1), a, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEmptyMap(t *testing.T) {
|
func TestEmptyMap(t *testing.T) {
|
||||||
|
@ -994,6 +994,10 @@ BigSwitch:
|
|||||||
p.buf.WriteByte('&')
|
p.buf.WriteByte('&')
|
||||||
p.printValue(a, verb, depth+1)
|
p.printValue(a, verb, depth+1)
|
||||||
break BigSwitch
|
break BigSwitch
|
||||||
|
case reflect.Map:
|
||||||
|
p.buf.WriteByte('&')
|
||||||
|
p.printValue(a, verb, depth+1)
|
||||||
|
break BigSwitch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
|
Loading…
x
Reference in New Issue
Block a user