Skip to content

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:

  1. Top (Arguments): You throw in raw ingredients (Numbers, Strings).
  2. Gears (Body): The machine processes them (Calculates, Formats).
  3. Bottom (Return): Processed meat comes out (Result).

9.2 Anatomy of a Function

go
// 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).

go
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.

go
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.

Released under the MIT License.