Chapter 09: Functions
"Don't repeat yourself (DRY)."
If you copy-paste the same code 3 times, you are creating a maintenance nightmare. We pack logic into reusable machines called Functions.
9.1 The Metaphor: The Meat Grinder
A function is like a meat grinder:
- Top (Arguments): You throw in raw ingredients (Numbers, Strings).
- Gears (Body): The machine processes them (Calculates, Formats).
- Bottom (Return): Processed meat comes out (Result).
9.2 Anatomy of a Function
// Keyword Name Inputs (Type) Outputs (Type)
func Add (a int, b int) int {
return a + b
}9.3 Multiple Returns
Unique to Go: A function can return multiple things. Usually, we return (Result, Error).
func Divide(a, b int) (int, error) {
if b == 0 {
return 0, fmt.Errorf("cannot divide by zero")
}
return a / b, nil
}The "Guard Clause" Pattern: Notice how we check for errors first and return early? This keeps our code clean (no nested else hell).
9.3b Idiomatic Naming: Getters
In Java, you might write GetName(). In Go, we just say Name().
- Bad:
GetOwner(),GetPrice(),GetAll() - Good:
Owner(),Price(),All()
If a function fetches something remotely or expensively, we usually just verb it directly (Fetch(), Find()). If it's a simple property access, drop the Get.
9.4 Practice: Interaction & Validation
In this lesson, we build a function that accepts User Input, validates it (checks for errors), and returns a safe result.
package main
import (
"html/template"
"log"
"net/http"
)
// Lesson 4: Interaction
// Goal: Accept user input via Forms and Validate it (The Quality Gate).
type Book struct {
Title string
Author string
}
var books = []Book{
{"The Go Gopher", "Rob Pike"},
}
const htmlTmpl = `
<!DOCTYPE html>
<head><link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"></head>
<body class="container py-5">
<h1>📚 The Gopher Shop</h1>
<!-- FORM -->
<form action="/add" method="POST" class="mb-4 row g-3">
<div class="col-auto"><input type="text" name="title" class="form-control" placeholder="Title"></div>
<div class="col-auto"><input type="text" name="author" class="form-control" placeholder="Author"></div>
<div class="col-auto"><button type="submit" class="btn btn-primary">Add Book</button></div>
</form>
<!-- LIST -->
<ul class="list-group">
{{range .}}
<li class="list-group-item">{{.Title}} ({{.Author}})</li>
{{end}}
</ul>
</body>
</html>
`
func main() {
tmpl, _ := template.New("index").Parse(htmlTmpl)
// GET: Show Page
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
tmpl.Execute(w, books)
})
// POST: Handle Data
http.HandleFunc("/add", func(w http.ResponseWriter, r *http.Request) {
title := r.FormValue("title")
author := r.FormValue("author")
// 🛡️ THE QUALITY GATE (Validation)
// Why? Never trust user input. It could be empty, malicious, or wrong.
// We reject bad data BEFORE it touches our database.
if title == "" {
http.Error(w, "Title cannot be empty!", http.StatusBadRequest)
return
}
// If good, add to shelf
books = append(books, Book{title, author})
http.Redirect(w, r, "/", http.StatusSeeOther)
})
log.Println("🚀 Shop v4 running on http://localhost:8080")
http.ListenAndServe(":8080", nil)
}🎓 Knowledge Check: What happens if we don't validate user input?
Answer: The "Quality Gate" stays open to garbage! Users could submit empty books, negative prices, or malicious code. Validation protects your database.
