DEV Community

Cover image for How I Stopped Worrying and Learned to Love Go Interfaces
Allan Githaiga
Allan Githaiga

Posted on

How I Stopped Worrying and Learned to Love Go Interfaces

Hey there, fellow Go newbies (or should I say Gophers-in-trainingšŸ•§)! šŸŒ±
Interfaces seemed like one of those mysterious, magical things that everyone kept talking about but no one really explained in a way that made sense. ā€œItā€™s like polymorphism but simpler,ā€ they said. ā€œItā€™s just like a contract,ā€ they claimed. But every time I tried to implement one, my code would look at me like, "What are you even doing, human?" šŸ‘€

But that was then. Now, interfaces and I are on much better terms, and I'm here to help you avoid my early confusion. So, if youā€™ve been scratching your head about Go interfaces, grab a cup of coffee (or tea), and letā€™s break it down, one step at a timeā€”minus the headaches. šŸ’”
So, What Exactly Is an Interface?

Letā€™s start from the very top. In Go, an interface is basically a way to define behavior, but without getting bogged down by the details of how it works. Imagine youā€™re the boss of a factory, and you donā€™t care how the machine works; you just care that it can produce the product. Thatā€™s what Go interfaces are like: you define what needs to happen, but not how it should be done.

For example, letā€™s pretend weā€™re working with animals (yes, Go works with animals, stay with me here). You know every animal makes a sound, but you donā€™t really care how that happens. Dogs bark, cats meow, and ducksā€¦well, they quack. You can define an interface like this:

type Animal interface {
    Sound() string
}

Enter fullscreen mode Exit fullscreen mode

Whatā€™s this?
Whatā€™s this? Just a contract, saying: "Hey, any type that wants to be called an Animal must have a Sound() method." Thatā€™s it! No weird wizardry involved.

Show Me the Code! šŸ¶šŸ±šŸ¦†

Letā€™s take a super simple example and see how it works in action. Weā€™ll create some animals and make them speak.

package main

import "fmt"

// The Animal interface
type Animal interface {
    Sound() string
}

// Define a Dog
type Dog struct{}

func (d Dog) Sound() string {
    return "Woof!"
}

// Define a Cat
type Cat struct{}

func (c Cat) Sound() string {
    return "Meow!"
}

func main() {
    // Our Animal variable can hold any type that satisfies the interface
    var myPet Animal

    // myPet is now a Dog
    myPet = Dog{}
    fmt.Println(myPet.Sound())  // Outputs: Woof!

    // myPet is now a Cat
    myPet = Cat{}
    fmt.Println(myPet.Sound())  // Outputs: Meow!
}

Enter fullscreen mode Exit fullscreen mode

Whatā€™s happening here?

  1. We define an Animal interface that has one method: Sound() šŸ”Š.
  2. Then we create two types, Dog and Cat, and give them their unique Sound() methods.
  3. In the main() function, we create a variable myPet that can hold anything that satisfies the Animal interface.
  4. First, we assign a Dog, and boom! Our dog barks: "Woof!" šŸ•
  5. Then we assign a Cat, and guess what? It meows: "Meow!" šŸˆ

Hereā€™s where the magic of Go interfaces really kicks in šŸ”„šŸ”„:
as long as a type has the required method, it satisfies the interface. No need to explicitly say "Dog implements Animal"ā€”Go is smart enough to figure it out on its own! šŸ§ šŸ’”

Why Should You Care About Interfaces?

why should i care
Let me level with you. At first, I was like, ā€œWhy even bother with this? I can just write my methods directly!ā€ But trust me, youā€™ll want to understand interfaces sooner rather than later, especially when your codebase starts to grow.

Hereā€™s why:

  1. Flexibility: Interfaces make your code more flexible. You can swap out one type for another as long as it satisfies the interface. Itā€™s like hiring someone based on their skills rather than their job title.
  2. Polymorphism: You can treat different types uniformly if they implement the same interface. This is what makes interfaces so powerfulā€”itā€™s like having a universal remote that works with any TV.

  3. Clean Code: Interfaces allow you to write cleaner, more modular code. You define behaviors and let the types handle their own implementation.

Multiple Methods, No Problem!

Letā€™s kick it up a notch. Say youā€™re building a system to work with shapes, and you want to calculate both area and perimeter for different shapes like circles and rectangles. Enter the multi-method interface!

package main

import "fmt"

// Shape interface with two methods
type Shape interface {
    Area() float64
    Perimeter() float64
}

// Rectangle struct
type Rectangle struct {
    Width, Height float64
}

func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

func (r Rectangle) Perimeter() float64 {
    return 2 * (r.Width + r.Height)
}

// Circle struct
type Circle struct {
    Radius float64
}

func (c Circle) Area() float64 {
    return 3.14 * c.Radius * c.Radius
}

func (c Circle) Perimeter() float64 {
    return 2 * 3.14 * c.Radius
}

func main() {
    var shape Shape

    shape = Rectangle{Width: 5, Height: 4}
    fmt.Println("Rectangle Area:", shape.Area())           // Outputs: 20
    fmt.Println("Rectangle Perimeter:", shape.Perimeter()) // Outputs: 18

    shape = Circle{Radius: 3}
    fmt.Println("Circle Area:", shape.Area())           // Outputs: 28.26
    fmt.Println("Circle Perimeter:", shape.Perimeter()) // Outputs: 18.84
}

Enter fullscreen mode Exit fullscreen mode

The Empty Interface (interface{})

Oh, you thought we were done?šŸ˜‚šŸ˜‚šŸ˜‚ Nope! Letā€™s go a bit deeper with the empty interface, interface{}, which is Goā€™s way of saying, ā€œI can hold any type.ā€ Itā€™s like a free-for-all box where you can throw in anythingā€”strings, numbers, structsā€”you name it.

package main

import "fmt"

func PrintAnything(val interface{}) {
    fmt.Println(val)
}

func main() {
    PrintAnything("Hello, Gophers!") // Outputs: Hello, Gophers!
    PrintAnything(42)                // Outputs: 42
    PrintAnything(true)              // Outputs: true
}

Enter fullscreen mode Exit fullscreen mode

The empty interface is often used in situations where you donā€™t know ahead of time what type youā€™ll be dealing with (think APIs or libraries). Itā€™s like Goā€™s version of a wildcard.

Embrace the Interface

Learning Go interfaces can feel like navigating a labyrinth at first, but once you grasp the basics, it opens up a whole new world of flexible, reusable, and clean code. So donā€™t be afraid to dive in!

Start simple, play with small examples, and let Goā€™s interface magic grow on you. Before long, youā€™ll be writing code thatā€™s as clean and flexible as a yoga instructor at a tech conference.

Happy coding, fellow Gophers! May your interfaces be simple, and your structs be ever-implementing. šŸ˜„āœŒļø

am done

Top comments (3)

Collapse
 
trapper99 profile image
Stanley Kariuki

If I may ask how do you make your blog banners especially the Go character?

Collapse
 
fredgitonga profile image
Fred

great article @githaiga22 , this is a nice and fun way to explain interfaces.

Collapse
 
victorpaularony profile image
Smally Pauls

nice learning interface and struct diffrances