From: Rob Pike String
must be of value type; this example used a
that's more efficient and idiomatic for struct types.
See the section below on pointers vs. value receivers for more information.)
Our String
method is able to call Sprintf
because the
-print routines are fully reentrant and can be used recursively.
-We can even go one step further and pass a print routine's arguments directly to another such routine.
+print routines are fully reentrant and can be wrapped this way.
+There is one important detail to understand about this approach,
+however: don't construct a String
method by calling
+Sprintf
in a way that will recur into your String
+method indefinitely. This can happen if the Sprintf
+call attempts to print the receiver directly as a string, which in
+turn will invoke the method again. It's a common and easy mistake
+to make, as this example shows.
+
+type MyString string + +func (m MyString) String() string { + return fmt.Sprintf("MyString=%s", m) // Error: will recur forever. +} ++ +
+It's also easy to fix: convert the argument to the basic string type, which does not have the +method. +
+ ++type MyString string +func (m MyString) String() string { + return fmt.Sprintf("MyString=%s", string(m)) // OK: note conversion. +} ++ +
+In the initialization section we'll see another technique that avoids this recursion. +
+ +
+Another printing technique is to pass a print routine's arguments directly to another such routine.
The signature of Printf
uses the type ...interface{}
for its final argument to specify that an arbitrary number of parameters (of arbitrary type)
can appear after the format.
@@ -1857,13 +1892,13 @@ while ByteSize(1e13)
prints as 9.09TB
.
-Note that it's fine to call Sprintf
and friends in the
-implementation of String
methods, but beware of
-recurring into the String
method through the nested
-Sprintf
call using a string format
-(%s
, %q
, %v
, %x
or %X
).
-The ByteSize
implementation of String
is safe
-because it calls Sprintf
with %f
.
+The use here of Sprintf
+to implement ByteSize
's String
method is safe
+(avoids recurring indefinitely) not because of a conversion but
+because it calls Sprintf
with %f
,
+which is not a string format: Sprintf
will only call
+the String
method when it wants a string, and %f
+wants a floating-point value.
-The conversion causes s
to be treated as an ordinary slice
-and therefore receive the default formatting.
-Without the conversion, Sprint
would find the
-String
method of Sequence
and recur indefinitely.
+This method is another example of the conversion technique for calling
+Sprintf
safely from a String
method.
Because the two types (Sequence
and []int
)
are the same if we ignore the type name, it's legal to convert between them.
The conversion doesn't create a new value, it just temporarily acts