In object-oriented programming, an “interface” is a description of the things an object can do. Usually, this takes the form of a list of methods an object is guaranteed to have. C# and Java both support interfaces, and so does the Go programming language, but Go’s interfaces are especially easy to use.
You don’t have to declare that a Go type (which can be used kind of like a “class” in other languages) implements an interface, like you do in C# or Java. You just declare the interface, and then any type that happens to have those methods can be used anywhere that interface is required.
Redundant Functions
Let’s suppose that I have a pets
package (a “package” is like a “library” in other languages) with Dog
and Cat
types. A Dog
has a Fetch
method, a Cat
has a Purr
method, and most importantly, both dogs and cats have Walk
and Sit
methods.
package pets
import "fmt"
type Dog struct {
Name string
Breed string
}
func (d Dog) Walk() {
fmt.Println(d.Name, "walks across the room")
}
func (d Dog) Sit() {
fmt.Println(d.Name, "sits down")
}
func (d Dog) Fetch() {
fmt.Println(d.Name, "fetches a toy")
}
type Cat struct {
Name string
Breed string
}
func (c Cat) Walk() {
fmt.Println(c.Name, "walks across the room")
}
func (c Cat) Sit() {
fmt.Println(c.Name, "sits down")
}
func (c Cat) Purr() {
fmt.Println(c.Name, "purrs")
}
Now, let’s create a demo.go
program that shows what the Dog
and Cat
types can do. We’ll create a DemoDog
function that takes a Dog
and calls its Walk
and Sit
methods. Then we’ll create a DemoCat
function that does the same thing, but for cats.
package main
import "pets"
func DemoDog(dog pets.Dog) {
dog.Walk()
dog.Sit()
}
func DemoCat(cat pets.Cat) {
cat.Walk()
cat.Sit()
}
func main() {
dog := pets.Dog{"Fido", "Terrier"}
cat := pets.Cat{"Fluffy", "Siamese"}
DemoDog(dog)
// The above call outputs:
// Fido walks across the room
// Fido sits down
DemoCat(cat)
// The above call outputs:
// Fluffy walks across the room
// Fluffy sits down
}
It’s too bad, though: the DemoDog
and DemoCat
functions are exactly the same, except that one takes a Dog
and the other takes a Cat
. Repeating code like that increases the risk of inconsistencies, since you might change one function but forget to update the other. It would be nice if we could get rid of DemoCat
and just pass a Cat
to DemoDog
, but we’ll get an error if we try that:
DemoDog(cat)
// ./demo.go:19: cannot use cat (type pets.Cat)
// as type pets.Dog in argument to DemoDog
Enter the Interface
But we don’t have to maintain two nearly-identical functions, just because they take different types. This is exactly the problem that interfaces are meant to solve.
We’ll just create a FourLegged
interface that includes all types with Walk
and Sit
methods. Then we’ll replace the DemoDog
and DemoCat
functions with a single Demo
function that takes any FourLegged
value (whether it’s a Dog
or a Cat
).
package main
import "pets"
// This interface represents any type
// that has both Walk and Sit methods.
type FourLegged interface {
Walk()
Sit()
}
// We can replace DemoDog and DemoCat
// with this single function.
func Demo(animal FourLegged) {
animal.Walk()
animal.Sit()
}
func main() {
dog := pets.Dog{"Fido", "Terrier"}
cat := pets.Cat{"Fluffy", "Siamese"}
Demo(dog)
// The above call (again) outputs:
// Fido walks across the room
// Fido sits down
Demo(cat)
// The above call (again) outputs:
// Fluffy walks across the room
// Fluffy sits down
}
The Awesome Part
We didn’t have to update the Dog
or Cat
types to declare that they implement the FourLegged
interface (like we would in C# or Java). We didn’t even have to open the pets
package. We just declared our interface right there in our main program, right above the function where we use it. And because they both have Walk
and Sit
methods, the Dog
and Cat
types are automatically usable any place in our code that calls for a FourLegged
value!
Go interfaces are a low-ceremony way to keep the safety of static typing (like you see in C# or Java), while still offering most of the flexibility of dynamic typing (like in JavaScript or Python). And they’re just one of the language’s many programmer-friendly features. If you’re suitably impressed, you should look into Go further; you won’t be disappointed!
P.S.: I’ve made the code from this post available in a Treehouse Workspaces snapshot. You can try running the code right from your browser by forking it and typing go run demo.go
in the workspace console.
P.P.S: This post was adapted from Go Language Overview. It’s our new course for developers already proficient in programming, who want a quick primer on Go. We’ll be releasing courses for beginning Go programmers too, so keep an eye on our library!
Start learning to code today with a free trial on Treehouse.
Great post. We’re featuring this in our news letter: https://betterdev.link/issues/6 to help other people find out it.
Thanks for including our post, we really appreciate it!
Go doesn’t have classic Object Oriented concept of classes and inheritance. Interfaces in Go provide a way to specify the behavior of an object: do like this and reuse it.