Interfaces in Go

Daniel

August 7, 2020

Interfaces in Go


Recently I started learning Go. Coming from a mostly Java background, interfaces in Go were a confusing concept.

From my Object-oriented programming knowledge I know what an interface is, and how to design one, however with no classes, how is it done?

Interface basics


Before we get into how interfaces work in Go, lets briefly talk about what an interface actually is.
An interface is a way to enforce certain properties on a class.
Its a concept of abstraction and encapsulation that allows you to define what goes into a function and what should come out.

In Java an interface may look like this:

public interface IVehicle
{
   void speedUp( final int a );

   void slowDown( final int a );

   String getPosition();
}

We then can write an implementing class that uses that interface.

public class VehicleImpl implements IVehicle

In the above example, you can see the method "speedUp" takes an int as a method argument and has no return value. We know that a vehicle that implements this class can speed up, down, and we can get the position. We have hidden the implementation of a vehicle away. We don't necessarily care how a vehicle speeds up, as long as it does.

So how is this done in Go?

Unlike Java, Go has no classes and no type hierarchy. Instead, Go provides structs which methods can be added onto. Let's look at an example using vehicles again.

type Vehicle interface {
  SpeedUp(a int)
  GetSpeed() int
}

type car struct {
  speed int
}

type boat struct {
  speed int
}

type plane struct {
  speed int
}

func (c *car) GetSpeed() int {
  return c.speed
}

func (c *car) SpeedUp(a int) {
  c.speed += a
}

func (b *boat) GetSpeed() int {
  return b.speed
}

func (b *boat) SpeedUp(a int) {
  b.speed += a / 2
}

func (p *plane) GetSpeed() int {
  return p.speed
}

func (p *plane) SpeedUp(a int) {
  p.speed *= a
}

Here we have defined a Vehicle interface and three structs representing our different types of vehicles. But as you can see, the "Vehicle" interface hasn't been used anywhere in these functions, why is that?

Go determines if a type satisfies an interface automatically. In our example, boat, plane and car all implement "SpeedUp" and "GetSpeed and therefore already satisfy the Vehicle interface. Notice we "dereference" (access the value of a pointer) a pointer to car, plane and boat (c *car). This is needed for out "SpeedUp" method to work else we will have passed the struct as a value and the speed won't change on the original struct.

Lets see the code in action:

func main() {
  vehicles := []Vehicle{&car{speed: 1}, &plane{speed: 1}, &boat{speed: 1}}
  for _, vehicle := range vehicles {
     vehicle.SpeedUp(10)
     fmt.Printf("%T is going %dmph\n", vehicle, vehicle.GetSpeed())
  }
}

The output of this is:

*main.car is going 11mph
*main.plane is going 10mph
*main.boat is going 6mph

Conclusion

We have successfully used the basics of the interface type in Go an created a small application. All the code used in this example can be found here https://play.golang.org/p/7NngH2-GmFQ.

The best way to learn is through practice, so give it a go yourself!

Daniel

Daniel

I am a Software Engineer working as part of the nerd.vision team, mainly working on the backend systems and agents. When I'm not squashing bugs, I enjoy travelling, gaming and experiencing new foods and cultures.