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?
interface{} means you can put value of any type, including your own custom type. All types in Go satisfy an empty interface ( interface{} is an empty interface). In your example, Msg field can have value of any type.
How to Create an Interface? In Go, you can create an interface using the type keyword, followed by the name of the interface and the keyword interface. And, you can specify method signatures inside curly braces. You will get to understand the creation of interfaces with examples.
map, pointer and slice types are reference types in Go. map, pointer, slice, channel, function and interface types are reference types.
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?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With