fmt.Printf("%v") panics where %#v doesn't

933 views
Skip to first unread message

Thorsten von Eicken

unread,
Jul 15, 2016, 4:22:29 PM7/15/16
to golang-nuts
I was surprised to see Printf %v panic on a struct that %#v prints fine. Is this expected / intentional / as designed?

Test case:
package main

import (
"fmt"
)

type MyError struct{ error }

func main() {
err := MyError{}
fmt.Printf("%%#v %#v\n", err)
fmt.Printf("%%+v %+v\n", err)
fmt.Printf("%%v %v\n", err)
}

Output:
%#v main.MyError{error:error(nil)}
%+v %!v(PANIC=runtime error: invalid memory address or nil pointer dereference)
%v %!v(PANIC=runtime error: invalid memory address or nil pointer dereference)

Matt Harden

unread,
Jul 15, 2016, 4:44:01 PM7/15/16
to Thorsten von Eicken, golang-nuts

I think MyError has the Error method, which %v will use but %#v will not. Then it panics because it's trying to call error(nil).Error().


--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Thorsten von Eicken

unread,
Jul 15, 2016, 5:03:25 PM7/15/16
to golang-nuts, t...@rightscale.com
You're probably correct, see this:

package main

import (
"fmt"
)

type MyError struct{ error }
type MyError2 struct {
foo int
err error
}

func main() {
err := MyError{}
fmt.Printf("%%#v %#v\n", err)
fmt.Printf("%%+v %+v\n", err)
fmt.Printf("%%v %v\n", err)

err2 := MyError2{}
fmt.Printf("%%#v %#v\n", err2)
fmt.Printf("%%+v %+v\n", err2)
fmt.Printf("%%v %v\n", err2)

var rr error
fmt.Printf("%%#v %#v\n", rr)
fmt.Printf("%%+v %+v\n", rr)
fmt.Printf("%%v %v\n", rr)
}

%#v main.MyError{error:error(nil)}
%+v %!v(PANIC=runtime error: invalid memory address or nil pointer dereference)
%v %!v(PANIC=runtime error: invalid memory address or nil pointer dereference)
%#v main.MyError2{foo:0, err:error(nil)}
%+v {foo:0 err:<nil>}
%v {0 <nil>}
%#v <nil>
%+v <nil>
%v <nil>

It's only if the error is embedded that it panics.

Matt Harden

unread,
Jul 15, 2016, 5:19:50 PM7/15/16
to Thorsten von Eicken, golang-nuts
This might make it clearer as well: https://play.golang.org/p/g3KdJUQRlK

Thorsten von Eicken

unread,
Jul 15, 2016, 5:38:02 PM7/15/16
to golang-nuts, t...@rightscale.com
Yup, doesn't quite make sense to me that Error() is called if it's an embedded struct and not when it's a struct field. See https://play.golang.org/p/Vp6Y-RETWZ

Chris Manghane

unread,
Jul 15, 2016, 5:49:04 PM7/15/16
to Thorsten von Eicken, golang-nuts
In your example, MyError2 does not have an Error() method so it is not called. From the fmt package docs (golang.org/pkg/fmt):
  • 3. If the %v verb is used with the # flag (%#v) and the operand implements the GoStringer interface, that will be invoked.
  • If the format (which is implicitly %v for Println etc.) is valid for a string (%s %q %v %x %X), the following... rules apply:
  • 4. If an operand implements the error interface, the Error method will be invoked to convert the object to a string, which will then be formatted as required by the verb (if any).
MyError implements the error interface and MyError2 does not.
Reply all
Reply to author
Forward
0 new messages