Back to Blog

Interfaces Tutorial - Polymorphism & Type Assertions | Learn Golang #17

Sandy LaneSandy Lane

Video: Interfaces Tutorial - Polymorphism & Type Assertions | Learn Golang #17 by Taught by Celeste AI - AI Coding Coach

Watch full page →

Interfaces Tutorial - Polymorphism & Type Assertions in Go

Interfaces in Go define a set of method signatures that types can implement implicitly, enabling polymorphism and flexible code design without explicit declarations. This tutorial demonstrates how to create and use interfaces, perform type assertions and switches, and implement the Stringer interface for custom string representations.

Code

package main

import (
  "fmt"
)

// Define an interface with a single method
type Speaker interface {
  Speak() string
}

// Implement Speaker implicitly for Dog type
type Dog struct {
  Name string
}

func (d Dog) Speak() string {
  return d.Name + " says Woof!"
}

// Implement Speaker implicitly for Cat type
type Cat struct {
  Name string
}

func (c Cat) Speak() string {
  return c.Name + " says Meow!"
}

// Use polymorphism: function accepts any Speaker
func announce(s Speaker) {
  fmt.Println(s.Speak())
}

func main() {
  dog := Dog{Name: "Buddy"}
  cat := Cat{Name: "Whiskers"}

  announce(dog) // Buddy says Woof!
  announce(cat) // Whiskers says Meow!

  // Empty interface can hold any type
  var i interface{} = dog

  // Type assertion to retrieve the concrete type
  if d, ok := i.(Dog); ok {
    fmt.Println("Type assertion succeeded:", d.Name)
  }

  // Type switch for multiple type checks
  switch v := i.(type) {
  case Dog:
    fmt.Println("It's a Dog named", v.Name)
  case Cat:
    fmt.Println("It's a Cat named", v.Name)
  default:
    fmt.Println("Unknown type")
  }
}

// Implementing the Stringer interface for custom formatting
func (d Dog) String() string {
  return "Dog: " + d.Name
}

Key Points

  • Interfaces define behavior through method signatures and are implemented implicitly in Go.
  • Polymorphism is achieved by accepting interface types, allowing different concrete types to be used interchangeably.
  • The empty interface interface{} can hold values of any type, enabling flexible data handling.
  • Type assertions extract the concrete type from an interface value, with type switches handling multiple type cases.
  • The Stringer interface customizes how types are formatted as strings, enhancing readability and debugging.