mirror of
https://github.com/golang/go
synced 2024-11-22 07:34:40 -07:00
fmt/Printf: document and tweak error messages produced for bad formats
R=golang-dev, adg CC=golang-dev https://golang.org/cl/2198044
This commit is contained in:
parent
d181625b9c
commit
344600f689
@ -69,8 +69,8 @@
|
|||||||
Regardless of the verb, if an operand is an interface value,
|
Regardless of the verb, if an operand is an interface value,
|
||||||
the internal concrete value is used, not the interface itself.
|
the internal concrete value is used, not the interface itself.
|
||||||
Thus:
|
Thus:
|
||||||
var i interface{} = 23;
|
var i interface{} = 23
|
||||||
fmt.Printf("%v\n", i);
|
fmt.Printf("%v\n", i)
|
||||||
will print 23.
|
will print 23.
|
||||||
|
|
||||||
If an operand implements interface Formatter, that interface
|
If an operand implements interface Formatter, that interface
|
||||||
@ -85,6 +85,26 @@
|
|||||||
cast the value before recurring:
|
cast the value before recurring:
|
||||||
func (x X) String() string { return Sprintf("%d", int(x)) }
|
func (x X) String() string { return Sprintf("%d", int(x)) }
|
||||||
|
|
||||||
|
Format errors:
|
||||||
|
|
||||||
|
If an invalid argument is given for a verb, such as providing
|
||||||
|
a string to %d, the generated string will contain a
|
||||||
|
description of the problem, as in these examples:
|
||||||
|
|
||||||
|
Wrong type or unknown verb: %!verb(type=value)
|
||||||
|
Printf("%d", hi): %!d(string=hi)
|
||||||
|
Too many arguments: %!(EXTRA type=value)
|
||||||
|
Printf("hi", "guys"): hi%!(EXTRA string=guys)
|
||||||
|
Too few arguments: %!verb(MISSING)
|
||||||
|
Printf("hi%d"): hi %!d(MISSING)
|
||||||
|
Non-int for width or precision: %!(BADWIDTH) or %!(BADPREC)
|
||||||
|
Printf("%*s", 4.5, "hi"): %!(BADWIDTH)hi
|
||||||
|
Printf("%.*s", 4.5, "hi"): %!(BADPREC)hi
|
||||||
|
|
||||||
|
All errors begin with the string "%!" followed sometimes
|
||||||
|
by a single character (the verb) and end with a parenthesized
|
||||||
|
description.
|
||||||
|
|
||||||
Scanning:
|
Scanning:
|
||||||
|
|
||||||
An analogous set of functions scans formatted text to yield
|
An analogous set of functions scans formatted text to yield
|
||||||
@ -97,7 +117,7 @@
|
|||||||
routines treat newlines as spaces.
|
routines treat newlines as spaces.
|
||||||
|
|
||||||
Scanf, Fscanf, and Sscanf parse the arguments according to a
|
Scanf, Fscanf, and Sscanf parse the arguments according to a
|
||||||
format string, analogous to that of Printf. For example, "%x"
|
format string, analogous to that of Printf. For example, %x
|
||||||
will scan an integer as a hexadecimal number, and %v will scan
|
will scan an integer as a hexadecimal number, and %v will scan
|
||||||
the default representation format for the value.
|
the default representation format for the value.
|
||||||
|
|
||||||
|
@ -193,8 +193,8 @@ var fmttests = []fmtTest{
|
|||||||
fmtTest{"%+.3g", complex128(1 + 2i), "(+1+2i)"},
|
fmtTest{"%+.3g", complex128(1 + 2i), "(+1+2i)"},
|
||||||
|
|
||||||
// erroneous formats
|
// erroneous formats
|
||||||
fmtTest{"", 2, "?(extra int=2)"},
|
fmtTest{"", 2, "%!(EXTRA int=2)"},
|
||||||
fmtTest{"%d", "hello", "%d(string=hello)"},
|
fmtTest{"%d", "hello", "%!d(string=hello)"},
|
||||||
|
|
||||||
// old test/fmt_test.go
|
// old test/fmt_test.go
|
||||||
fmtTest{"%d", 1234, "1234"},
|
fmtTest{"%d", 1234, "1234"},
|
||||||
@ -301,7 +301,7 @@ var fmttests = []fmtTest{
|
|||||||
fmtTest{"%s", I(23), `<23>`},
|
fmtTest{"%s", I(23), `<23>`},
|
||||||
fmtTest{"%q", I(23), `"<23>"`},
|
fmtTest{"%q", I(23), `"<23>"`},
|
||||||
fmtTest{"%x", I(23), `3c32333e`},
|
fmtTest{"%x", I(23), `3c32333e`},
|
||||||
fmtTest{"%d", I(23), `%d(string=<23>)`},
|
fmtTest{"%d", I(23), `%!d(string=<23>)`},
|
||||||
|
|
||||||
// go syntax
|
// go syntax
|
||||||
fmtTest{"%#v", A{1, 2, "a", []int{1, 2}}, `fmt_test.A{i:1, j:0x2, s:"a", x:[]int{1, 2}}`},
|
fmtTest{"%#v", A{1, 2, "a", []int{1, 2}}, `fmt_test.A{i:1, j:0x2, s:"a", x:[]int{1, 2}}`},
|
||||||
@ -321,7 +321,7 @@ var fmttests = []fmtTest{
|
|||||||
|
|
||||||
// renamings
|
// renamings
|
||||||
fmtTest{"%v", renamedBool(true), "true"},
|
fmtTest{"%v", renamedBool(true), "true"},
|
||||||
fmtTest{"%d", renamedBool(true), "%d(fmt_test.renamedBool=true)"},
|
fmtTest{"%d", renamedBool(true), "%!d(fmt_test.renamedBool=true)"},
|
||||||
fmtTest{"%o", renamedInt(8), "10"},
|
fmtTest{"%o", renamedInt(8), "10"},
|
||||||
fmtTest{"%d", renamedInt8(-9), "-9"},
|
fmtTest{"%d", renamedInt8(-9), "-9"},
|
||||||
fmtTest{"%v", renamedInt16(10), "10"},
|
fmtTest{"%v", renamedInt16(10), "10"},
|
||||||
@ -366,14 +366,14 @@ var fmttests = []fmtTest{
|
|||||||
fmtTest{"%p", make(chan int), "PTR"},
|
fmtTest{"%p", make(chan int), "PTR"},
|
||||||
fmtTest{"%p", make(map[int]int), "PTR"},
|
fmtTest{"%p", make(map[int]int), "PTR"},
|
||||||
fmtTest{"%p", make([]int, 1), "PTR"},
|
fmtTest{"%p", make([]int, 1), "PTR"},
|
||||||
fmtTest{"%p", 27, "%p(int=27)"}, // not a pointer at all
|
fmtTest{"%p", 27, "%!p(int=27)"}, // not a pointer at all
|
||||||
|
|
||||||
// erroneous things
|
// erroneous things
|
||||||
fmtTest{"%d", "hello", "%d(string=hello)"},
|
fmtTest{"%d", "hello", "%!d(string=hello)"},
|
||||||
fmtTest{"no args", "hello", "no args?(extra string=hello)"},
|
fmtTest{"no args", "hello", "no args%!(EXTRA string=hello)"},
|
||||||
fmtTest{"%s", nil, "%s(<nil>)"},
|
fmtTest{"%s", nil, "%!s(<nil>)"},
|
||||||
fmtTest{"%T", nil, "<nil>"},
|
fmtTest{"%T", nil, "<nil>"},
|
||||||
fmtTest{"%-1", 100, "%1(int=100)"},
|
fmtTest{"%-1", 100, "%!1(int=100)"},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSprintf(t *testing.T) {
|
func TestSprintf(t *testing.T) {
|
||||||
@ -622,12 +622,12 @@ var startests = []starTest{
|
|||||||
starTest{"%-*d", args(4, 42), "42 "},
|
starTest{"%-*d", args(4, 42), "42 "},
|
||||||
|
|
||||||
// erroneous
|
// erroneous
|
||||||
starTest{"%*d", args(nil, 42), "%(badwidth)42"},
|
starTest{"%*d", args(nil, 42), "%!(BADWIDTH)42"},
|
||||||
starTest{"%.*d", args(nil, 42), "%(badprec)42"},
|
starTest{"%.*d", args(nil, 42), "%!(BADPREC)42"},
|
||||||
starTest{"%*d", args(5, "foo"), "%d(string= foo)"},
|
starTest{"%*d", args(5, "foo"), "%!d(string= foo)"},
|
||||||
starTest{"%*% %d", args(20, 5), "% 5"},
|
starTest{"%*% %d", args(20, 5), "% 5"},
|
||||||
starTest{"%*", args(4), "%(badwidth)%*(int=4)"},
|
starTest{"%*", args(4), "%!(BADWIDTH)%!*(int=4)"},
|
||||||
starTest{"%*d", args(int32(4), 42), "%(badwidth)42"},
|
starTest{"%*d", args(int32(4), 42), "%!(BADWIDTH)42"},
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: there's no conversion from []T to ...T, but we can fake it. These
|
// TODO: there's no conversion from []T to ...T, but we can fake it. These
|
||||||
|
@ -20,12 +20,12 @@ var (
|
|||||||
nilParenBytes = []byte("(nil)")
|
nilParenBytes = []byte("(nil)")
|
||||||
nilBytes = []byte("nil")
|
nilBytes = []byte("nil")
|
||||||
mapBytes = []byte("map[")
|
mapBytes = []byte("map[")
|
||||||
missingBytes = []byte("missing")
|
missingBytes = []byte("(MISSING)")
|
||||||
extraBytes = []byte("?(extra ")
|
extraBytes = []byte("%!(EXTRA ")
|
||||||
irparenBytes = []byte("i)")
|
irparenBytes = []byte("i)")
|
||||||
bytesBytes = []byte("[]byte{")
|
bytesBytes = []byte("[]byte{")
|
||||||
widthBytes = []byte("%(badwidth)")
|
widthBytes = []byte("%!(BADWIDTH)")
|
||||||
precBytes = []byte("%(badprec)")
|
precBytes = []byte("%!(BADPREC)")
|
||||||
)
|
)
|
||||||
|
|
||||||
// State represents the printer state passed to custom formatters.
|
// State represents the printer state passed to custom formatters.
|
||||||
@ -266,6 +266,7 @@ func (p *pp) unknownType(v interface{}) {
|
|||||||
|
|
||||||
func (p *pp) badVerb(verb int, val interface{}) {
|
func (p *pp) badVerb(verb int, val interface{}) {
|
||||||
p.add('%')
|
p.add('%')
|
||||||
|
p.add('!')
|
||||||
p.add(verb)
|
p.add(verb)
|
||||||
p.add('(')
|
p.add('(')
|
||||||
if val == nil {
|
if val == nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user