-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions and Methods
-
Section 4: Concurrency
-
Section 5: Packages and Tooling
-
Section 6: More Standard Library
-
Section 7: Building Services
-
Section 8: Advanced Go
-
Section 9: Go in the Cloud-Native Ecosystem
-
Section 10: Data Structures and Algorithms in Go
-
Section 11: Testing and Deployment
-
Section 12: Practical Projects
-
Section 13: More Standard Library Practice
-
Section 14: More Practice Projects
-
Section 15: Design Patterns in Go
-
Section 16: Interview Practice
-
Section 17: Package fmt In Depth
-
Section 18: Package strings and strconv
-
Section 19: Package os and io
-
Section 20: Package time
-
Section 21: Package sort and container
-
Section 22: Package encoding
-
Section 23: Package net/http In Depth
-
Section 24: Package context
-
Section 25: Package regexp and bytes
-
Section 26: Package errors In Depth
-
Section 27: Package crypto and hash
-
Section 28: Package flag and log
-
Section 29: Package sync In Depth
-
Section 30: More Practice Exercises
-
Section 31: Go Modules and Workspaces In Depth
-
Section 32: Generics Deep Dive (Go 1.18+)
-
Section 33: Testing Package In Depth
-
Section 34: More Interview and Whiteboard Practice
-
Section 35: Package math and unicode
-
Section 36: Package path and filepath
-
Section 37: Package database/sql
-
Section 38: Package text/template and html/template
-
Section 39: Package archive and compress
-
Section 40: Lower-Level net Package
-
Section 41: Package runtime and reflect
-
Section 42: Package embed and io/fs
-
Section 43: Go Assembly and CGO Basics
-
Section 44: Building CLIs and TUIs
-
Section 45: Go Performance Tuning
-
Section 46: More Real-World Projects
-
Section 47: Go in Production
-
Section 48: Go Design Patterns
-
Section 49: Go Interfaces Deep Dive
-
Section 50: Final Practice and Review
16: Practice Exercise: Building a Simple Inventory Struct System
Imagine you're running a small warehouse. You can't possibly keep every single detail of every product in your head, so you use an index card system. Each card represents one product. On that card, you've got specific slots: one for the product name, one for the SKU number, one for the current quantity on the shelf, and one for the price. If you want to know about a "Mechanical Keyboard," you pull the card, look at the slots, and there's your data.
In Go, a struct is exactly that index card. It's a way of grouping different types of data together under one name so you aren't passing five different variables around your program. Instead of having a name string and a quantity int floating around independently, you bundle them into an Item. When you have a whole drawer of these cards, you've got a slice of structs.
Defining the Product Blueprint
When I'm designing a system like this, I start by thinking about the "minimum viable data." For an inventory system, we don't need the product's history or manufacturer's address—just the essentials. Here is how we translate that index card into Go code:
type Item struct {
SKU string
Name string
Quantity int
Price float64
}
Notice that I've capitalized the field names. In Go, this makes them "exported," meaning other packages can see them. Even if we're staying in main for this exercise, it's a good habit to get into. I've used a float64 for the price, which is fine for a simple exercise, though in a real production financial system, I'd probably tell you to use integers to represent cents to avoid floating-point errors. But let's keep it simple for now.
Managing the Collection
A single Item is great, but a warehouse is a collection. We use a slice to hold our inventory. I like to initialize my data using a slice literal—it's much cleaner than calling append ten times in a row.
inventory := []Item{
{SKU: "KB-001", Name: "Mechanical Keyboard", Quantity: 15, Price: 89.99},
{SKU: "MS-002", Name: "Wireless Mouse", Quantity: 30, Price: 25.50},
{SKU: "MN-003", Name: "4K Monitor", Quantity: 5, Price: 349.00},
}
Updating Stock without Creating Copies
Here is where most people trip up when they first start with structs: values versus pointers. If you write a function to reduce stock and you pass the Item by value, Go makes a complete copy of that "index card." You'll scribble a new quantity on the copy, throw the copy in the trash, and the original card in the warehouse remains unchanged.
To actually change the inventory, we need a pointer. By using *Item, we're telling Go, "Don't copy the card; give me the address of the actual card in the drawer."
func (i *Item) Sell(amount int) {
if i.Quantity >= amount {
i.Quantity -= amount
fmt.Printf("Sold %d of %s\n", amount, i.Name)
} else {
fmt.Println("Insufficient stock!")
}
}
I've used a method here instead of a standalone function. It just reads more naturally: item.Sell(1) feels like a real-world action. It's a small detail, but it makes your code much more intuitive for whoever has to read it after you.
📋 Practical Task
Exercise: The Boutique Electronics Stock Manager
Your goal is to build a small CLI tool that manages a boutique electronics store's inventory. You need to implement a system that can track items and handle sales.
Requirements:
- Define an
Itemstruct with fields forSKU(string),Name(string),Quantity(int), andPrice(float64). - Create a slice containing at least three different electronics products.
- Implement a method called
Restockthat takes anamount intas an argument and increases the item's quantity. - Implement a method called
Sellthat takes anamount int. It should decrease the quantity only if there is enough stock; otherwise, it should print "Error: Not enough stock for [Item Name]". - In your
mainfunction:- Print the initial inventory.
- Sell 2 units of one item.
- Attempt to sell 100 units of another item (to trigger the error).
- Restock an item that is running low.
- Print the final state of the inventory to verify the changes.
There are no comments for now.