Courses/Go/Structs and Interfaces

    Lesson 4 • Intermediate

    Structs and Interfaces 🐹

    Group data with structs, write flexible code with interfaces, and understand Go's composition-over-inheritance philosophy.

    What You'll Learn in This Lesson

    • • Defining structs with fields and struct tags
    • • Composition with embedded structs
    • • Interfaces and implicit satisfaction
    • • Type assertions and type switches
    • • Pointers and memory addresses

    1️⃣ Structs

    Structs are Go's way to group related data together. Unlike classes in OOP languages, structs don't support inheritance — Go uses composition (embedding) instead. Struct tags control JSON/DB serialization.

    Try It: Structs

    Define structs, embed them, and use struct tags

    Try it Yourself »
    JavaScript
    // Structs — Custom Data Types
    console.log("=== Defining Structs ===");
    console.log();
    console.log("type User struct {");
    console.log("    ID       int");
    console.log("    Name     string");
    console.log("    Email    string");
    console.log("    IsActive bool");
    console.log("}");
    console.log();
    
    // Simulate
    const user = { ID: 1, Name: "Alice", Email: "alice@dev.com", IsActive: true };
    console.log("// Creating instances:");
    console.log('u1 := User{ID: 1, Name: "Alice", Email: "alice@dev.com", IsAct
    ...

    2️⃣ Interfaces

    Go interfaces are implicitly satisfied — no implements keyword. If a type has the right methods, it automatically satisfies the interface. This enables powerful polymorphism without tight coupling.

    Try It: Interfaces

    Define interfaces and see implicit satisfaction

    Try it Yourself »
    JavaScript
    // Interfaces — Implicit Satisfaction
    console.log("=== What Are Interfaces? ===");
    console.log("An interface defines a set of method signatures.");
    console.log("Any type that implements those methods satisfies the interface.");
    console.log("No 'implements' keyword needed — it's IMPLICIT!");
    console.log();
    
    console.log("type Shape interface {");
    console.log("    Area() float64");
    console.log("    Perimeter() float64");
    console.log("}");
    console.log();
    
    // Simulate with objects
    const circle = {
      
    ...

    3️⃣ Interface Composition & Type Assertions

    Compose small interfaces into larger ones. Use type assertions to extract the concrete type from an interface value, and type switches for polymorphic behavior.

    Try It: Composition

    Compose interfaces and use type assertions

    Try it Yourself »
    JavaScript
    // Interface Composition & Type Assertions
    console.log("=== Composing Interfaces ===");
    console.log();
    console.log("type Reader interface {");
    console.log("    Read(p []byte) (n int, err error)");
    console.log("}");
    console.log();
    console.log("type Writer interface {");
    console.log("    Write(p []byte) (n int, err error)");
    console.log("}");
    console.log();
    console.log("type ReadWriter interface {");
    console.log("    Reader    // Embeds Reader");
    console.log("    Writer    // Embeds Writer");
    cons
    ...

    4️⃣ Pointers

    Pointers hold memory addresses. Use them to modify values inside functions and avoid copying large structs. Go auto-dereferences struct pointers and forbids pointer arithmetic — keeping things safe.

    Try It: Pointers

    Memory addresses, dereferencing, and pointer safety

    Try it Yourself »
    JavaScript
    // Pointers in Go
    console.log("=== Pointers — Memory Addresses ===");
    console.log();
    console.log("  x := 42");
    console.log("  p := &x        // p is a pointer to x");
    console.log("  fmt.Println(*p)  // 42 — dereference to get value");
    console.log("  *p = 100       // Modify through pointer");
    console.log("  fmt.Println(x)   // 100 — x is changed!");
    console.log();
    
    let x = 42;
    console.log("  x =", x);
    console.log("  p := &x");
    console.log("  *p = 100");
    x = 100;
    console.log("  x =", x, "(modifie
    ...

    ⚠️ Common Mistakes

    ⚠️
    Nil pointer dereference — Accessing fields on a nil pointer causes a runtime panic. Always check for nil.
    ⚠️
    Large interfaces — Go convention: keep interfaces small (1-3 methods). "The bigger the interface, the weaker the abstraction." — Rob Pike
    💡
    Pro Tip: Accept interfaces, return structs. This gives callers flexibility while keeping your return types concrete.

    📋 Quick Reference

    PatternGo Syntax
    Structtype User struct { Name string }
    Interfacetype Stringer interface { String() string }
    Embeddingtype Admin struct { User }
    Type assertv, ok := i.(Type)
    Pointerp := &x; *p = 10

    🎉 Lesson Complete!

    You understand structs, interfaces, and pointers — Go's core building blocks. Next, we'll unlock Go's superpower: concurrency with goroutines!

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy PolicyTerms of Service