Reputation: 169
Link: https://play.golang.org/p/69I8PAuoAV
Extract:
package main
import "fmt"
type Stringer interface {
String() string
}
type fakeString struct {
content string
}
// function used to implement the Stringer interface
func (s *fakeString) String() string {
return s.content
}
func printString(value interface{}) {
switch str := value.(type) {
case string:
fmt.Println(str)
case Stringer:
fmt.Println(str.String())
}
}
func main() {
s := &fakeString{"Ceci n'est pas un string"}
printString(s)
printString("Hello, Gophers")
}
The printString(s)
function call when reaching case matches the case Stringer
part.
s
is of type *fakeString
not Stringer
.
Why does it match Stringer
.
I did a fmt.Println(reflect.TypeOf(str))
and it confirmed the type as *main.fakeString
Upvotes: 1
Views: 1473
Reputation: 13981
This is interface satisfaction in golang.
There are two kinds of type in golang: interface type and concrete type.
concrete type
works exactly as you expected in switch
: the variable is an instance of the given typeinterface type
on the other hand works differently, it checks if the variable satisfies the interface.Hum, safisfies? How does it work?
A (concrete) type satisfies an interface if it possesses all the methods the interface requires.
-- the golang programming language
In the case, Stringer
is an interface, declaring only one method: String() string
. And fakeString
satisfies it by having its own String() string
method.
Two things to note however:
Upvotes: 1
Reputation: 5123
In Go to satisfy an interface all you have to do is implement the methods of that interface nothing else. In this case to have a behavior as a Stringer you have to implement String() string
, so the type fakeString behaves as a Stringer because implement that method; in terms of OOP we use interfaces just to define behavior not types or values. So you may be implementing Go interfaces all day without knowing, but not big deal, it only matters when you have to satisfy behaviors.
Actually in a real project you may want to add a default
case to your switch in the method printString
, to detect when the interface{} is something else, like this:
func printString(value interface{}) {
switch str := value.(type) {
case string:
fmt.Println("string", str)
case Stringer:
fmt.Println("Stringer", str.String())
default:
fmt.Printf("unexpected type: %T value: '%v'", str, str)
}
}
// main:
printString(2)
https://play.golang.org/p/pmxSXfUu4e
Upvotes: 4