Core Concepts

Structs and Interfaces

Build complex types with Go structs and define behavior with interfaces.

Structs

Go uses structs instead of classes. Methods can be attached to any type.

Methods

Methods are functions with a receiver argument. Pointer receivers allow modification of the struct.

Interfaces

Go interfaces are implicitly satisfied — no implements keyword needed. If a type has all the methods an interface requires, it satisfies the interface automatically.

This is a powerful form of duck typing with static type checking.

Embedding

Go uses composition through embedding instead of inheritance.

Example

go
package main

import (
    "fmt"
    "math"
)

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

type Circle struct {
    Radius float64
}

// Methods with value receiver (read-only)
func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

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

// Method with pointer receiver (can modify struct)
func (r *Rectangle) Scale(factor float64) {
    r.Width *= factor
    r.Height *= factor
}

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

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

// Interface - implicitly satisfied
type Shape interface {
    Area() float64
    Perimeter() float64
}

func printShapeInfo(s Shape) {
    fmt.Printf("Area: %.2f, Perimeter: %.2f\n", s.Area(), s.Perimeter())
}

// Embedding (composition over inheritance)
type Animal struct {
    Name string
}

func (a Animal) Speak() string {
    return a.Name + " says..."
}

type Dog struct {
    Animal   // embed Animal
    Breed string
}

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

func main() {
    r := Rectangle{Width: 5, Height: 3}
    c := Circle{Radius: 4}

    printShapeInfo(r)  // Works! Rectangle satisfies Shape
    printShapeInfo(c)  // Works! Circle satisfies Shape

    r.Scale(2)
    fmt.Printf("Scaled: %.0f x %.0f\n", r.Width, r.Height)

    // Polymorphism with interface slice
    shapes := []Shape{
        Rectangle{Width: 3, Height: 4},
        Circle{Radius: 5},
    }
    for _, s := range shapes {
        fmt.Printf("%.2f\n", s.Area())
    }

    // Embedding
    dog := Dog{Animal: Animal{Name: "Rex"}, Breed: "Labrador"}
    fmt.Println(dog.Speak())   // Rex says: Woof!
    fmt.Println(dog.Name)       // Accessing embedded field
}
Try it yourself — GO