McElfresh Blog

Go, PostgreSQL, MySQL, Ruby, Rails, Sinatra, etc.

Go Interfaces Part 2

Posted at — Jan 7, 2025

Method Sets: Assignment

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:

Assign a Concrete Value to an Interface Value

Try it on The Go Playground

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)

Pass a Concrete Type as a Method Parameter

Try it on The Go Playground

 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}

Give a Struct Field an Interface Type

Try it on The Go Playground

 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}

Return an Interface Type from a Function

Try it on The Go Playground

 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}

Assign a Concrete Value to an Embedded Interface Field

Try it on The Go Playground

 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}

Variations and Notes

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: