Go AdvancedFebruary 07, 2025

Go Interfaces - Complete Guide

Learn about Go interfaces, how they work, and how to use them effectively. Understand interface implementation and polymorphism in Go.

Author: Sushil Kumar

golanginterfacespolymorphismprogramming

Go Interfaces - Complete Guide

Interfaces are one of Go's most powerful features. They let you define behavior without specifying implementation. If you understand interfaces, you'll write better, more flexible Go code!

What is an Interface?

An interface defines a set of methods. Any type that implements those methods automatically satisfies the interface. No explicit declaration needed!

Think of an interface as a contract - it says "if you can do these things, you're this type."

type Shape interface {
    Area() float64
    Perimeter() float64
}

Basic Interface Syntax

type InterfaceName interface {
    Method1() ReturnType
    Method2(param Type) ReturnType
}

Simple Example

package main
 
import "fmt"
 
// Define interface
type Speaker interface {
    Speak() string
}
 
// Define struct
type Dog struct {
    Name string
}
 
// Implement interface (implicitly)
func (d Dog) Speak() string {
    return fmt.Sprintf("%s says: Woof!", d.Name)
}
 
func main() {
    var speaker Speaker
    speaker = Dog{Name: "Buddy"}
    fmt.Println(speaker.Speak())  // Buddy says: Woof!
}

Interface Implementation

In Go, you don't explicitly say "this type implements this interface." If a type has all the methods an interface requires, it automatically implements that interface!

type Writer interface {
    Write([]byte) (int, error)
}
 
// Any type with Write method implements Writer
type File struct {}
func (f File) Write(data []byte) (int, error) {
    // Implementation
    return len(data), nil
}
 
// File automatically implements Writer!

Multiple Interfaces

A type can implement multiple interfaces:

type Reader interface {
    Read([]byte) (int, error)
}
 
type Writer interface {
    Write([]byte) (int, error)
}
 
type ReadWriter interface {
    Reader
    Writer
}
 
// A type that implements Read and Write automatically implements ReadWriter

Empty Interface

The empty interface interface{} accepts any type:

func printAnything(v interface{}) {
    fmt.Println(v)
}
 
printAnything(42)        // Works
printAnything("hello")   // Works
printAnything(true)      // Works

Note: In Go 1.18+, use any instead of interface{} - it's shorter!

Interface Values

Interface values contain:

  1. A concrete type
  2. A value of that type
var w Writer
w = File{}  // w now contains type File and value File{}

Type Assertions

Extract the concrete type from an interface:

var i interface{} = "hello"
 
s := i.(string)        // Type assertion
fmt.Println(s)         // "hello"
 
s, ok := i.(string)    // Safe type assertion
if ok {
    fmt.Println(s)
}

Type Switches

Switch on interface type:

func printType(v interface{}) {
    switch v := v.(type) {
    case int:
        fmt.Println("Integer:", v)
    case string:
        fmt.Println("String:", v)
    case bool:
        fmt.Println("Boolean:", v)
    default:
        fmt.Println("Unknown type")
    }
}

Common Interfaces

Stringer Interface

type Stringer interface {
    String() string
}
 
type Person struct {
    Name string
    Age  int
}
 
func (p Person) String() string {
    return fmt.Sprintf("%s (%d years old)", p.Name, p.Age)
}
 
func main() {
    p := Person{Name: "John", Age: 25}
    fmt.Println(p)  // Uses String() method automatically
}

Error Interface

type error interface {
    Error() string
}
 
type MyError struct {
    Message string
}
 
func (e MyError) Error() string {
    return e.Message
}

Real-World Example: Shape Interface

package main
 
import (
    "fmt"
    "math"
)
 
type Shape interface {
    Area() float64
    Perimeter() float64
}
 
type Circle struct {
    Radius float64
}
 
func (c Circle) Area() float64 {
    return math.Pi * c.Radius * c.Radius
}
 
func (c Circle) Perimeter() float64 {
    return 2 * math.Pi * c.Radius
}
 
type Rectangle struct {
    Width  float64
    Height float64
}
 
func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}
 
func (r Rectangle) Perimeter() float64 {
    return 2 * (r.Width + r.Height)
}
 
func printShapeInfo(s Shape) {
    fmt.Printf("Area: %.2f, Perimeter: %.2f\n", s.Area(), s.Perimeter())
}
 
func main() {
    circle := Circle{Radius: 5}
    rectangle := Rectangle{Width: 4, Height: 6}
    
    printShapeInfo(circle)     // Works!
    printShapeInfo(rectangle)   // Works!
}

Visual Explanation: Interface Implementation

Here's how interfaces work:

Interface Definition:
┌─────────────────────────────┐
│ type Writer interface {     │
│     Write([]byte) error     │
│ }                           │
└─────────────────────────────┘

         │ Any type with Write method
         │ automatically implements it

    ┌────┴────┬────────┬────────┐
    │         │        │        │
    ▼         ▼        ▼        ▼
┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐
│ File │ │Buffer│ │Network│ │Memory│
│      │ │      │ │      │ │      │
│Write │ │Write │ │Write │ │Write │
└──────┘ └──────┘ └──────┘ └──────┘
    │         │        │        │
    └─────────┴────────┴────────┘


    All can be used as Writer!

Interface Composition

Combine interfaces:

type Reader interface {
    Read([]byte) (int, error)
}
 
type Writer interface {
    Write([]byte) (int, error)
}
 
type Closer interface {
    Close() error
}
 
// Compose interfaces
type ReadWriteCloser interface {
    Reader
    Writer
    Closer
}

Frequently Asked Questions (FAQ)

Q1: How do I know if a type implements an interface?

A: If a type has all the methods an interface requires, it automatically implements that interface. Go checks this at compile time. No explicit declaration needed!

Q2: Can an interface have no methods?

A: Yes! The empty interface interface{} (or any in Go 1.18+) accepts any type. It's useful when you need to accept any value.

Q3: Can I add methods to an interface later?

A: Yes, but it might break existing code. If you add methods to an interface, all types implementing it must also implement the new methods.

Q4: What's the difference between interface{} and any?

A: They're the same! any is just an alias for interface{} introduced in Go 1.18. Use any for cleaner code.

Q5: Can interfaces have fields?

A: No! Interfaces only define methods, not fields. They describe behavior, not data.

Q6: What happens if a type doesn't implement all interface methods?

A: Go will give a compile-time error. The type won't satisfy the interface until it implements all required methods.

Q7: Can I create an interface with just one method?

A: Yes! Single-method interfaces are common and powerful:

type Stringer interface {
    String() string
}

Q8: What's the difference between interface and struct?

A:

  • Interface - Defines behavior (methods)
  • Struct - Defines data (fields)

Interfaces say "what you can do," structs say "what you are."

Q9: Can I use interfaces with pointers?

A: Yes! You can implement interfaces with pointer receivers:

type Writer interface {
    Write([]byte) (int, error)
}
 
type File struct {}
 
func (f *File) Write(data []byte) (int, error) {
    // Implementation
}
 
var w Writer = &File{}  // Use pointer

Q10: When should I use interfaces?

A: Use interfaces when:

  • You want to accept multiple types
  • You want to decouple code
  • You want to make code testable
  • You want to define behavior contracts

Don't overuse - use them when they add value!


Next Steps

Now that you understand interfaces, here's what to learn next:

Interfaces are powerful in Go. Practice using them to write flexible, testable code!