A concrete type implements an interface where it implements at least all that interface’s methods.
We can assign a concrete type to an interface variable in five ++ ways:
1package main
2import "fmt"
3
4var i interface{}
5n := 1
6// Set interface value's concrete object to n
7i = n
8fmt.Println("i: %d\n", i)
1package main
2
3import "fmt"
4
5type cat struct{}
6func (c cat) speak() {
7 fmt.Println("meow")
8}
9type speaker interface{
10 speak()
11}
12func do(animal speaker) {
13 animal.speak()
14}
15
16func main() {
17 c := new(cat)
18 // we can pass in a cat to our "do" method, because a cat
19 // is a speaker
20 do(c)
21}
1package main
2
3import "fmt"
4
5type cat struct{}
6
7func (c cat) speak() {
8 fmt.Println("meow")
9}
10
11type speaker interface{
12 speak()
13}
14
15type zoo struct {
16 // A cat is a speaker
17 animal speaker
18}
19
20func (z zoo) do() {
21 z.animal.speak()
22}
23
24func main() {
25 c := new(cat)
26 z := zoo {
27 animal: c,
28 }
29 z.do()
30}
1package main
2
3import "fmt"
4
5type myInt int
6
7// myInt implements fmt.Stringer
8func (n myInt) String() string {
9 return fmt.Sprintf("%d", n)
10}
11
12func main() {
13 i := n(1)
14 fmt.Printf("myInt: %d\n", i)
15}
16
17func n(n myInt) fmt.Stringer {
18 return n
19}
1package main
2
3import "fmt"
4
5type wrapper struct {
6 fmt.Stringer
7}
8
9type myInt int
10
11func (m myInt) String() string {
12 return fmt.Sprintf("MyInt: %d", m)
13}
14
15func main() {
16 n := myInt(42)
17 // Concrete type assigned via embedding
18 w := wrapper{Stringer: n}
19 fmt.Printf("myInt: %d\n", w)
20}
There are many variations along the lines of assigning a concrete variable to an interface value for a map, slice, channel, etc.
Important to understand: