Interfaces
An interface is a set of methods. We can define an interface by listing out the methods it's expected to support. For example, consider the following interface:
var a interface {
check()
}
Here we are defining a to be a variable that has the type interface{ check() }. What on earth does that mean?
It means that you can put any value into a, as long as the value has a type that has a method called check().
Why is this valuable? It's valuable when considering multiple types that do similar things. Consider the following:
type complicatedEmail struct {...}
func (e complicatedEmail) check() {...}
func (e complicatedEmail) send(a string) {...}
type simpleEmail string
func (e simpleEmail) check() {...}
func (e simpleEmail) send(a string) {...}
Now we want to write a function do, which does two things:
- Check that an email address is correct
- Send "Hello World" to the email
You would need two do functions:
func doC(a complicatedEmail) {
a.check()
a.send("Hello World")
}
func doS(a simpleEmail) {
a.check()
a.send("Hello World")
}
Instead, if that's all the bodies of the functions are, we may opt to do this:
func do(a interface{
check()
send(a string)
}) {
a.check()
a.send("Hello World")
}
This is quite hard to read. So let's give the interface a name:
type checkSender interface{
check()
send(a string)
}
Then we can simply redefine do to be the following:
func do(a checkSender) {
a.check()
a.send("Hello World")
}
A note on naming interfaces in Go. It is customary to name interfaces with a -er suffix. If a type implements check(), then the interface name should be called checker. This encourages the interfaces to be small. An interface should only define a small number of methods—larger interfaces are signs of poor program design.