mirror of
https://github.com/golang/go
synced 2024-11-25 01:08:02 -07:00
fmt/print: honor Formatter in Print, Println.
Rearrange code to clarify handling of %T, Formatter, GoStringer, and Stringer. R=rsc CC=golang-dev https://golang.org/cl/1973043
This commit is contained in:
parent
e2bde5cf9b
commit
be97fa4c79
@ -78,6 +78,23 @@ type C struct {
|
||||
B
|
||||
}
|
||||
|
||||
type F int
|
||||
|
||||
func (f F) Format(s State, c int) {
|
||||
Fprintf(s, "<%c=F(%d)>", c, int(f))
|
||||
}
|
||||
|
||||
type G int
|
||||
|
||||
func (g G) GoString() string {
|
||||
return Sprintf("GoString(%d)", int(g))
|
||||
}
|
||||
|
||||
type S struct {
|
||||
f F // a struct field that Formats
|
||||
g G // a struct field that GoStrings
|
||||
}
|
||||
|
||||
var b byte
|
||||
|
||||
var fmttests = []fmtTest{
|
||||
@ -322,6 +339,15 @@ var fmttests = []fmtTest{
|
||||
fmtTest{"%v", renamedComplex64(3 + 4i), "(3+4i)"},
|
||||
fmtTest{"%v", renamedComplex128(4 - 3i), "(4-3i)"},
|
||||
|
||||
// Formatter
|
||||
fmtTest{"%x", F(1), "<x=F(1)>"},
|
||||
fmtTest{"%x", G(2), "2"},
|
||||
fmtTest{"%+v", S{F(4), G(5)}, "{f:<v=F(4)> g:5}"},
|
||||
|
||||
// GoStringer
|
||||
fmtTest{"%#v", G(6), "GoString(6)"},
|
||||
fmtTest{"%#v", S{F(7), G(8)}, "fmt_test.S{f:<v=F(7)>, g:GoString(8)}"},
|
||||
|
||||
// %T
|
||||
fmtTest{"%T", (4 - 3i), "complex"},
|
||||
fmtTest{"%T", renamedComplex128(4 - 3i), "fmt_test.renamedComplex128"},
|
||||
@ -546,3 +572,22 @@ func TestBlankln(t *testing.T) {
|
||||
t.Errorf("got %q expected %q", got, expect)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check Formatter with Sprint, Sprintln, Sprintf
|
||||
func TestFormatterPrintln(t *testing.T) {
|
||||
f := F(1)
|
||||
expect := "<v=F(1)>\n"
|
||||
s := Sprint(f, "\n")
|
||||
if s != expect {
|
||||
t.Errorf("Sprint wrong with Formatter: expected %q got %q\n", expect, s)
|
||||
}
|
||||
s = Sprintln(f)
|
||||
if s != expect {
|
||||
t.Errorf("Sprintln wrong with Formatter: expected %q got %q\n", expect, s)
|
||||
}
|
||||
s = Sprintf("%v\n", f)
|
||||
if s != expect {
|
||||
t.Errorf("Sprintf wrong with Formatter: expected %q got %q\n", expect, s)
|
||||
}
|
||||
}
|
||||
|
@ -493,18 +493,44 @@ var (
|
||||
)
|
||||
|
||||
func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth int) (wasString bool) {
|
||||
if field != nil {
|
||||
switch {
|
||||
default:
|
||||
if stringer, ok := field.(Stringer); ok {
|
||||
p.printField(stringer.String(), verb, plus, goSyntax, depth)
|
||||
return false // this value is not a string
|
||||
}
|
||||
case goSyntax:
|
||||
if stringer, ok := field.(GoStringer); ok {
|
||||
p.printField(stringer.GoString(), verb, plus, goSyntax, depth)
|
||||
return false // this value is not a string
|
||||
}
|
||||
if field == nil {
|
||||
if verb == 'T' || verb == 'v' {
|
||||
p.buf.Write(nilAngleBytes)
|
||||
} else {
|
||||
p.badVerb(verb, field)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Special processing considerations.
|
||||
// %T (the value's type) is special; we always do it first.
|
||||
if verb == 'T' {
|
||||
p.printField(reflect.Typeof(field).String(), 's', false, false, 0)
|
||||
return false
|
||||
}
|
||||
// Is it a Formatter?
|
||||
if formatter, ok := field.(Formatter); ok {
|
||||
formatter.Format(p, verb)
|
||||
return false // this value is not a string
|
||||
|
||||
}
|
||||
// Must not touch flags before Formatter looks at them.
|
||||
if plus {
|
||||
p.fmt.plus = false
|
||||
}
|
||||
// If we're doing Go syntax and the field knows how to supply it, take care of it now.
|
||||
if goSyntax {
|
||||
p.fmt.sharp = false
|
||||
if stringer, ok := field.(GoStringer); ok {
|
||||
// Print the result of GoString unadorned.
|
||||
p.fmtString(stringer.GoString(), 's', false, field)
|
||||
return false // this value is not a string
|
||||
}
|
||||
} else {
|
||||
// Is it a Stringer?
|
||||
if stringer, ok := field.(Stringer); ok {
|
||||
p.printField(stringer.String(), verb, plus, false, depth)
|
||||
return false // this value is not a string
|
||||
}
|
||||
}
|
||||
|
||||
@ -580,15 +606,6 @@ func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth
|
||||
return verb == 's'
|
||||
}
|
||||
|
||||
if field == nil {
|
||||
if verb == 'v' {
|
||||
p.buf.Write(nilAngleBytes)
|
||||
} else {
|
||||
p.badVerb(verb, field)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
value := reflect.NewValue(field)
|
||||
// Need to use reflection
|
||||
// Special case for reflection values that know how to print with %p.
|
||||
@ -802,33 +819,8 @@ func (p *pp) doPrintf(format string, a []interface{}) {
|
||||
field := a[fieldnum]
|
||||
fieldnum++
|
||||
|
||||
// %T is special; we always do it here.
|
||||
if c == 'T' {
|
||||
// the value's type
|
||||
if field == nil {
|
||||
p.buf.Write(nilAngleBytes)
|
||||
break
|
||||
}
|
||||
p.printField(reflect.Typeof(field).String(), 's', false, false, 0)
|
||||
continue
|
||||
}
|
||||
|
||||
// Try Formatter (except for %T).
|
||||
if field != nil {
|
||||
if formatter, ok := field.(Formatter); ok {
|
||||
formatter.Format(p, c)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
goSyntax := c == 'v' && p.fmt.sharp
|
||||
if goSyntax {
|
||||
p.fmt.sharp = false
|
||||
}
|
||||
plus := c == 'v' && p.fmt.plus
|
||||
if plus {
|
||||
p.fmt.plus = false
|
||||
}
|
||||
p.printField(field, c, plus, goSyntax, 0)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user