This question already has an answer here:
fmt.Println calling Error instead of String()
(1 answer)
Closed 2 months ago.
In the below code the type ErrNegativeSqrt implements both Stringer and error interfaces. Since in Sqrt method the return type is fmt.Stringer, I would except the execution result to be:
0 nil
0 Impl Stringer type
But the actual result is the following, why?
0 nil
0 Impl error type
package main
import (
"fmt"
)
type ErrNegativeSqrt float64
func Sqrt(x ErrNegativeSqrt) (float64, fmt.Stringer) {
if x < 0 {
return 0, ErrNegativeSqrt(x)
}
return 0, nil
}
func (e ErrNegativeSqrt) String() string {
return "Impl Stringer type"
}
func (e ErrNegativeSqrt) Error() string {
return "Impl error type"
}
func main() {
fmt.Println(Sqrt(2))
fmt.Println(Sqrt(-2))
}
The documentation for Package fmt states that:
... special formatting
considerations apply for operands that implement certain interfaces.
In order of application:
...
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 two rules apply:
If an operand implements the error interface, the Error method will be invoked ...
If an operand implements method String() string, that method will be invoked ...
Since you are using fmt.Println, rules 4 and 5 come into play, which prefers to call Error() over String()
You're ignoring the fact that your function returns a fmt.Stringer by passing the resulting value to fmt.Println as an interface{}.
You see the result from the Error() method only because the fmt package checks for the error interface before it checks for the fmt.Stringer interface.
Related
The program below prints "2.5"
package main
import (
"fmt"
)
type myFloat64 float64
// func (f myFloat64) Error() string {
// return fmt.Sprintf("Error with %v", f)
// }
func main() {
var a myFloat64 = myFloat64(2.5)
fmt.Printf("%v\n", a)
}
Interestingly, when I uncomment the Error() method, the program no longer prints "2.5"
Question:
Why does adding an Error() method change program behavior? Pointers to the Go language specification explaining this behavior would be much appreciated.
myFloat64 implements the error interface:
type error interface {
Error() string
}
fmt.Println() will consider a as an error value, and print the error message by calling a.Error(), which executes fmt.Sprintf("Error with %v", f). But Sprintf behaves just like Println, it also considers f as an error value and calls Error(). This recursion goes infinitely and causes stack overflow.
This question already has answers here:
Pointers vs. values in parameters and return values
(5 answers)
When to use pointers [duplicate]
(1 answer)
Difference between returning a pointer and a value in initialization methods [duplicate]
(1 answer)
Why should constructor of Go return address?
(2 answers)
Why should I use a pointer ( performance)?
(3 answers)
Closed 1 year ago.
I am doing a tour of go language, and I have a question about pointers.
Example code (https://tour.golang.org/methods/19):
package main
import (
"fmt"
"time"
)
type MyError struct {
When time.Time
What string
}
func (e *MyError) Error() string {
return fmt.Sprintf("at %v, %s",
e.When, e.What)
}
func run() error {
return &MyError{
time.Now(),
"it didn't work",
}
}
func main() {
if err := run(); err != nil {
fmt.Println(err)
}
}
In this case it is using *MyError and &MyError, but I try to remove the * and & and it works correctly. Why are they using pointers in this example? What is the difference with normal variables? When should I use pointers or not?
"When should I use pointers?" is a very large question without a simple answer. Pointers are a way of passing a reference to a value, rather than a value itself, around, allowing you to modify the original value or "see" modifications to that value. It also prevents copying, which can be a performance improvement in very limited circumstances (do not pass pointers around all the time because it might be a performance improvement). Finally, pointers also let you represent "nothingness", which each pointer being able to be nil. This is both a blessing and a curse as you must check if each pointer is nil before accessing it, though.
In your specific example, the reason why returning &MyError works is because your Error() function operates on a value of *MyError (a pointer to MyError), rather than on a value of MyError itself. This means that *MyError implements the Error interface and is thus assignable to the error type, and so it can be returned from any function that expects an error as a return value.
Returning MyError wouldn't work on its own because MyError is not a *MyError. Go does some helpful things when dealing with function receivers: It will let you call any method on a MyError or *MyError if the receiver is *MyError, but it will only let you call methods on a *MyError if the type is *MyError - That is, Go will not "create" a pointer for you out of thin air.
If you were to remove * from func (e* MyError), you would be telling Go that Error() works on any instance of a MyError, which means that both *MyError and MyError would fulfill that contract. That's why both of the following are valid when you don't use a pointer receiver:
func (e MyError) Error() string {}
var _ error = MyError{} // Valid
var _ error = &MyError {}
In this particular case, using pointers will not make a difference. Here's one way to look at it:
In Go, all variables are passed by value. That means:
type T struct {...}
func f(value T) {..}
f(t)
Above, t is passed as value. That means when f is called, the compiler creates a copy of t and passed that to f. Any modifications f makes to that copy will not affect the t used to call f.
If you use pointers:
func f(value *T) {...}
f(&t)
Above, the compiler will create a pointer pointing to t, and pass a copy of that to f. If f makes changes to value, those changes will be made on the instance of t used to call f. In other words:
type T struct {
x int
}
func f(value T) {
value.x=1
}
func main() {
t:=T{}
f(t)
fmt.Println(t.x)
}
This will print 0, because the modifications made by f is done on a copy of t.
func f(value *T) {
value.x=1
}
func main() {
t:=T{}
f(&t)
fmt.Println(t.x)
}
Above, it will print 1, because the call to f changes t.
Same idea applies to methods and receivers:
type T struct {
x int
}
func (t T) f() {
t.x=1
}
func main() {
t:=T{}
t.f()
fmt.Println(t.x)
}
Above program will print 0, because the method modifies a copy of t.
func (t *T) f() {
t.x=1
}
func main() {
t:=T{}
t.f()
fmt.Println(t.x)
}
Above program will print 1, because the receiver of the method is declared with a pointer, and calling t.f() is equivalent to f(&t).
So, use pointers when passing arguments or when declaring methods if you want to modify the object, or if copying the object would be too expensive.
This is only a small part of the story about pointer arguments.
Reading through the 7.8 section of "The Go Programming Language" I spotted following code:
var err error = syscall.Errno(2)
fmt.Println(err.Error()) // "no such file or directory"
fmt.Println(err) // "no such file or directory"
I understand the first and second line. error interface is saitisfied by syscall.Errno, thus Error() function returning string is available.
I don't understand third one. Going through syscall's sources I can't find any place where syscall.Errno satisfies stringer interface - String() function is not defined.
Why third one prints string representation of sysscall.Errno?
The answer is found in the fmt documentation here:
If the format (which is implicitly %v for Println etc.) is valid for a string (%s %q %v %x %X), the following two rules apply:
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).
If an operand implements method String() string, that method will be invoked to convert the object to a string, which will then be formatted as required by the verb (if any).
So actually, for any value that supports both, the String() method is never called at all, since the error interface takes precidence over the Stringer interface. You can test this with a program like this one:
package main
import (
"fmt"
)
type foo string
func (f foo) String() string {
return "string"
}
func (f foo) Error() string {
return "error"
}
func main() {
fmt.Println(foo(""))
}
Output:
error
I have been reading about function types as interface values in go and I came across an example that I have not been able to figure out. Here it is:
type binFunc func(int, int) int
func add(x, y int) int { return x + y }
func (f binFunc) Error() string { return "binFunc error" }
func main() {
var err error
err = binFunc(add)
fmt.Println(err)
}
You can find it on Go Playground here.
I understand that you can assign a method to a function type, but I do not understand how Error() is being called.
The docs for the fmt package have this to say:
Except when printed using the verbs %T and %p, special formatting
considerations apply for operands that implement certain interfaces.
In order of application:
...
If the format (which is implicitly %v for Println etc.) is valid for a
string (%s %q %v %x %X), the following two rules apply:
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).
If an operand implements method String() string, that method will be invoked to convert the object to a string, which will then be
formatted as required by the verb (if any).
In other words, fmt.Println will attempt to print the string representation of the interface. Since the error interface is satisfied by binFunc, it invokes the Error method of binFunc.
I don't understand at which point an Interface method is being called. I'm looking at the following example from the Go Tour:
package main
import "fmt"
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
}
func main() {
a := Person{"Arthur Dent", 42}
z := Person{"Zaphod Beeblebrox", 9001}
fmt.Println(a, z)
}
Problem:
I understand that the func (p Person) receives the String() method and that it returns the string I want to display. But the fmt.Println in the main() method has to call String() at some point, right?
I had a look at the source of fmt in godoc, but I still cannot figure it out!
Another example:
If I add my own interface, lets say Stringer2 with a method called String2() and then create a func (p Person) String2() {....}.
How does String() get executed by fmt.Println, but String2() not?
The value is passed to Println as an interface{}, and is checked if it satisfies the fmt.Stringer interface via a "type assertion" often in the form of a "type switch".
func IsStringer(i interface{}) {
switch s := i.(type) {
case fmt.Stringer:
fmt.Println("Person a has a String() method")
fmt.Println(s.String())
default:
fmt.Println("not a stringer")
}
// OR for a single type
if s, ok := i.(fmt.Stringer); ok {
fmt.Println("Person a has a String() method")
fmt.Println(s.String())
}
}
However, other methods may take precedence when printing from the fmt package. There are first checks for fmt.Formatter, fmt.GoStringer, error, and then finally fmt.Stringer.
The fmt package works with the interfaces it defines, in this case Stringer. It does not know of interfaces defined by you so it wouldn't know to call String2() even if you pass it a type that meets the Stringer2 interface.
Interfaces are a way to have common behavior between types. So if you create a function Foo(s Stringer2), Foo can simply call s.String2() confident that anything passed into it will have the function String2().
To go a bit deeper, fmt.Println takes interface{} types and then uses reflection to check if the given argument meets the Stringer interface to then call String().
Make sense?