Mastering Go: Slices, Maps, Structs, Methods and Interfaces

Introduction

This week, we explored key Go concepts, such as slices, maps, structs, methods and interfaces. To reinforce our learning, we built a Geometry Tracker, a mini project that ties everything together. In this article, we’ll break down our approach, explain how each components works, and reflect on the lessons learned.

Key Concepts We Covered

Slices

  • A dynamic array-like data structure in Go.
  • Used to store multiple shapes in our project.

Maps

  • A key-value store, allowing us to track shape areas.
  • Used to store the total area of different shape types.

Struct

  • A way to define complex data types.
  • Used to define Circle and Rectangle with relevant attributes.

Methods

  • Functions associated with a structs.
  • Used to compute the area and return the name of each shape

Interfaces

  • Defines a set of method signatures that structs must implement.
  • Used to enforce a consistent API across different shape types.

Building the Geometry Tracker

  1. Define the Shape Interface
// Shape interface for all geometric figures
type Shape interface {
  Area() float64
  Name() string
  String() string
}
Go

2 . Implementing Structs for Shapes

// Circle struct
type Circle struct {
 Radius float64
}

type Recatangle struct {
  Width, Height float64
}
Go

3 . Implementing Methods for Shapes

func (c Circle) Area() float64 {
  return math.Pi * c.Radius * c.Radius
}
func (c Circle) Name() string {
  return "Circle"
}
func (c Circle) String() string {
  return fmt.Sprintf("%s (Radius: %.2f, Area: %.2f)":, c.Name(), c,Raduis, c.Area())
}
func (r Rectangle) Area() float64 {
 return r.width * r.Height
}
func (r Rectangle) Name() string {
  return "Rectangle"
}
func (r Rectangle) String() string {
  return fmt.Sprintf("%s (Width: %.2f, Height: %.2f, Area: %.2f)", r.Name(), r.width, r.Height, r.Area()) 
}
Go

4 . Creating the Geometry Tracker

type GeometryTracker struct {
    Shapes     []Shape         // Stores multiple shapes
    AreaLookup map[string]float64 // Tracks total area per shape type
}

// AddShape method
func (gt *GeometryTracker) AddShape(s Shape) {
    gt.Shapes = append(gt.Shapes, s)
    gt.AreaLookup[s.Name()] += s.Area()
}

// TotalArea method
func (gt GeometryTracker) TotalArea() float64 {
    total := 0.0
    for _, shape := range gt.Shapes {
        total += shape.Area()
    }
    return total
}

// Display all shapes
func (gt GeometryTracker) DisplayShapes() {
    for _, shape := range gt.Shapes {
        fmt.Println(shape)
    }
    fmt.Println("\nTotal Area:", gt.TotalArea())
Go

Running the Program

func main() {
    tracker := GeometryTracker{
        Shapes:     []Shape{},
        AreaLookup: make(map[string]float64),
    }

    // Add shapes
    tracker.AddShape(Circle{Radius: 5})
    tracker.AddShape(Rectangle{Width: 4, Height: 6})
    tracker.AddShape(Circle{Radius: 3})

    // Display all shapes
    tracker.DisplayShapes()

    // Print area breakdown
    fmt.Println("\nArea Breakdown:")
    for shape, area := range tracker.AreaLookup {
        fmt.Printf("%s: %.2f\n", shape, area)
    }
}
Go

Example output

Circle (Radius: 5.00, Area: 78.54)
Rectangle (Width: 4.00, Height: 6.00, Area: 24.00)
Circle (Radius: 3.00, Area: 28.27)

Total Area: 130.81

Area Breakdown:
Circle: 106.81
Rectangle: 24.00

For the “Geometry Tracker” mini-project, the architecture follows a modular and extensible design based on Go’s core principles. Let’s break it down:

1. Architectural Style: Modular & Interface-Based Design

• Uses structs and interfaces to model geometric shapes.

• Leverages slices to store multiple shape instances.

• Implements maps for efficient lookup and area tracking.

• Applies method chaining for better usability.

• Utilizes the Stringer interface for human-readable output.

2. Layered Structure

a) Data Layer (Structs & Fields)

• Defines the Circle and Rectangle structs to represent geometric shapes.

• Uses fields for dimensions (e.g., radius for circles, width & height for rectangles).

b) Behavior Layer (Methods & Interfaces)

• Implements a Shape interface with a Area() method for polymorphism.

• Implements String() using the fmt.Stringer interface for meaningful output.

c) Storage & Processing Layer

• Uses a slice ([]Shape) to store multiple shape instances dynamically.

• Uses a map (map[string]float64) to efficiently track shape names and their computed areas.

d) Application Layer (Main Logic)

• Initializes shapes.

• Stores them in the slice.

• Computes and prints total areas.

• Formats output for clarity.

3. Design Patterns & Principles Used

Encapsulation – Shapes have private fields accessed via methods.

Polymorphism – The Shape interface allows different types of shapes to be processed uniformly.

Composition over Inheritance – No deep inheritance trees, just simple struct-based composition.

Separation of Concerns – Data (structs), logic (methods), and storage (slices/maps) are cleanly separated.

Open/Closed Principle – New shapes (e.g., Triangle) can be added without modifying existing code.

4. Final Folder Structure (If Extended into a Larger Project)

geometry-tracker/
│── main.go         # Entry point for the application
│── shapes/
│   │── shape.go    # Defines the Shape interface
│   │── circle.go   # Implements the Circle struct & methods
│   │── rectangle.go # Implements the Rectangle struct & methods
│── storage/
│   │── store.go    # Manages slices/maps for shape storage
│── utils/
│   │── format.go   # Helper functions for formatting & output
│── go.mod         # Go module file

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *