Shine on you crazy interface
Go's interfaces are brilliant. It's not immediately apparent and at first can be confusing, but after a while its brilliance shines through.
TL;DR - if a concrete type has the necessary behavior (methods) to satisfy an interface, it can implicitly implement that interface.
In Go, interfaces are considered abstract types, meaning we do not know what an interface really is, only what it can do.
The Go standard library makes use of interfaces, let's take a look at an example. Say we have the following (see it in the Go Playground):
type song struct {
name string
release time.Time
}
type songs []song
func (s songs) String() string {
var ss []string
for i := range s {
ss = append(ss, s[i].name+" "+fmt.Sprint(s[i].release.Year()))
}
return strings.Join(ss, ", ")
}
s := songs{
{"Comfortably Numb", time.Date(1979, time.November, 0, 0, 0, 0, 0, time.UTC)},
{"Interstellar Overdrive", time.Date(1967, time.August, 0, 0, 0, 0, 0, time.UTC)},
{"Time", time.Date(1973, time.March, 0, 0, 0, 0, 0, time.UTC)},
{"High Hopes", time.Date(1994, time.March, 0, 0, 0, 0, 0, time.UTC)},
}
fmt.Println(s)
// Comfortably Numb 1979, Interstellar Overdrive 1967, Time 1973, High Hopes 1994
Say we want to sort the above based on release date so we can listen to Pink Floyd in chronological order. We could write our own sorting function, but instead, let's see if we can implement the sort.Sort from the standard library:
func Sort(data Interface)
// where Interface is an abstract type that has three methods
type Interface interface {
// comments omitted for brevity
Len() int
Less(i, j int) bool
Swap(i, j int)
}
So to implement sort.Interface
we write the following three methods for our songs
type:
func (s songs) Len() int {
return len(s)
}
func (s songs) Less(i, j int) bool {
return s[i].release.Before(s[j].release)
}
func (s songs) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
The sort.Sort
function doesn't care about the underlying type. So long as the type has behavior
through its methods that implements Len
, Less
and Swap
it can be sorted... (usually)
sort.Sort(s)
fmt.Println(s)
// Interstellar Overdrive 1967, Time 1973, Comfortably Numb 1979, High Hopes 1994
Note as of Go 1.8 it's even easier to implement slice sort. See go1.8#sort_slice
Example can be found here: https://play.golang.org/p/8b2OokpqsLA
// to implement sort.Slice all we need is the Less method from above, omit Len and Swap entirely
// func Slice(slice interface{}, less func(i, j int) bool)
sort.Slice(s, s.Less)
fmt.Println(s)
// Interstellar Overdrive 1967, Time 1973, Comfortably Numb 1979, High Hopes 1994
To wrap things up, we were able to leverage a standard library sorting function through an
interface. Our concrete type songs
implicitly implemented the sort.Sort
function because it had
the necessary behavior (methods). The interface type sort.Interface
defined the contract between
sort.Sort
and its caller.
These are the types of quality of life improvements that make Go a joy to work with.