}
var (
- osErrorType = reflect.TypeOf(new(os.Error)).Elem()
+ osErrorType = reflect.TypeOf((*os.Error)(nil)).Elem()
+ fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
)
// evalCall executes a function or method call. If it's a method, fun already has the receiver bound, so
}
switch v.Kind() {
case reflect.Ptr:
- var isNil bool
- if v, isNil = indirect(v); isNil {
- fmt.Fprint(s.wr, "<nil>")
- return
- }
+ v, _ = indirect(v) // fmt.Fprint handles nil.
case reflect.Chan, reflect.Func, reflect.Interface:
s.errorf("can't print %s of type %s", n, v.Type())
}
+ // If it's a value but the pointer implements Stringer, use the pointer.
+ if v.Kind() != reflect.Ptr && v.CanAddr() && reflect.PtrTo(v.Type()).Implements(fmtStringerType) {
+ v = v.Addr()
+ }
fmt.Fprint(s.wr, v.Interface())
}
ComplexZero float64
// Nested structs.
U *U
+ // Struct with String method.
+ V0 V
+ V1, V2 *V
// Slices
SI []int
SIEmpty []int
V string
}
+type V struct {
+ j int
+}
+
+func (v *V) String() string {
+ if v == nil {
+ return "nilV"
+ }
+ return fmt.Sprintf("<%d>", v.j)
+}
+
var tVal = &T{
True: true,
I: 17,
U16: 16,
X: "x",
U: &U{"v"},
+ V0: V{6666},
+ V1: &V{7777}, // leave V2 as nil
SI: []int{3, 4, 5},
SB: []bool{true, false},
MSI: map[string]int{"one": 1, "two": 2, "three": 3},
{"$.U.V", "{{$.U.V}}", "v", tVal, true},
{"declare in action", "{{$x := $.U.V}}{{$x}}", "v", tVal, true},
+ // Type with String method.
+ {"V{6666}.String()", "-{{.V0}}-", "-<6666>-", tVal, true},
+ {"&V{7777}.String()", "-{{.V1}}-", "-<7777>-", tVal, true},
+ {"(*V)(nil).String()", "-{{.V2}}-", "-nilV-", tVal, true},
+
// Pointers.
{"*int", "{{.PI}}", "23", tVal, true},
{"*[]int", "{{.PSI}}", "[21 22 23]", tVal, true},