Go > Structs and Interfaces > Interfaces > Defining interfaces

Defining and Implementing Interfaces in Go

This example demonstrates how to define and implement interfaces in Go. Interfaces define a set of methods that a type must implement to satisfy the interface. This promotes polymorphism and code reusability.

Defining an Interface

This code defines an interface called Shape with two methods: Area() and Perimeter(). The Rectangle and Circle structs both implement the Shape interface by providing implementations for the Area() and Perimeter() methods. The printShapeInfo function accepts any type that implements the Shape interface, demonstrating polymorphism.

package main

import "fmt"

// Shape interface defines the methods that a shape must implement.
type Shape interface {
    Area() float64
    Perimeter() float64
}

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

// Circle struct
type Circle struct {
    Radius float64
}

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

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

// Area method for Circle
func (c Circle) Area() float64 {
    return 3.14159 * c.Radius * c.Radius
}

// Perimeter method for Circle
func (c Circle) Perimeter() float64 {
    return 2 * 3.14159 * c.Radius
}

// Function that takes a Shape interface as an argument
func printShapeInfo(s Shape) {
    fmt.Printf("Area: %.2f\n", s.Area())
    fmt.Printf("Perimeter: %.2f\n", s.Perimeter())
}

func main() {
    rect := Rectangle{Width: 5, Height: 10}
    circ := Circle{Radius: 7}

    printShapeInfo(rect)
    printShapeInfo(circ)
}

Concepts Behind the Snippet

The core concepts here are interfaces and polymorphism. An interface defines a contract that types can fulfill. Polymorphism allows you to write code that works with any type that satisfies a given interface, without knowing the specific type at compile time. Go uses implicit interface satisfaction, meaning that a type automatically implements an interface if it defines all of the interface's methods.

Real-Life Use Case

Imagine you are building a system for processing different types of documents (e.g., PDFs, Word documents, text files). You could define an interface called Document with methods like Parse(), Validate(), and ExtractText(). Each specific document type would then implement the Document interface, allowing your system to process any document type in a uniform way.

Best Practices

  • Keep interfaces small and focused on specific behavior.
  • Design interfaces to represent common abstractions in your domain.
  • Avoid defining interfaces that are too generic or too specific.

Interview Tip

Be prepared to explain the difference between interfaces and structs. Also, be ready to discuss the benefits of using interfaces for achieving loose coupling and testability. Understanding the concept of implicit interface satisfaction is crucial.

When to Use Them

Use interfaces when you want to:

  • Define a common set of operations that different types should support.
  • Decouple code dependencies.
  • Create more testable code (by mocking interface implementations).

Memory Footprint

Interfaces themselves have a small memory footprint. They typically consist of two words: one for the type information and one for the value. However, the memory footprint of the underlying concrete type will depend on its own structure.

Alternatives

While interfaces are the primary mechanism for abstraction in Go, you could potentially use type assertions or type switches in some limited scenarios. However, these approaches are generally less flexible and maintainable than using interfaces.

Pros

  • Promotes code reusability through polymorphism.
  • Enables loose coupling, making code more modular and maintainable.
  • Facilitates unit testing by allowing you to mock dependencies.

Cons

  • Can add a layer of indirection, potentially impacting performance in some cases (though this is often negligible).
  • Requires careful design to avoid creating overly complex or brittle interfaces.

FAQ

  • What is implicit interface satisfaction?

    In Go, a type automatically satisfies an interface if it implements all of the methods defined by the interface. There is no explicit declaration required.
  • Can a struct implement multiple interfaces?

    Yes, a struct can implement multiple interfaces. It simply needs to implement all of the methods defined by each interface.
  • What happens if a struct only implements some of the methods of an interface?

    The struct will not be considered to implement the interface. You will get a compile-time error if you try to use it as a value of that interface type.