Notes — Module 3: Functions¶
These are your personal study notes. Write freely and honestly. Incomplete notes are fine — they show where your understanding still needs work. Return to this file to add insights as they develop over time.
Module: [[go/3. Functions]] Topic: [[go]] Date started: YYYY-MM-DD Status: In progress
Concept Map¶
Sketch how the concepts in this module relate to each other. Fill in the Mermaid diagram.
mindmap
root((Functions))
Declarations and Signatures
parameter shorthand (x, y int)
multiple return types
named return values
Call-by-Value
scalars copied independently
slices share backing array
maps share hash table
pointers dereference to original
Multiple Return Values
(result, error) convention
error always last
_ to discard values
Named Returns and Naked Returns
documentation value
defer interaction
avoid in long functions
error idiom
errors.New
fmt.Errorf with %w
nil means success
Variadic Functions
...T parameter is a slice
spread with slice...
only last param can be variadic
First-Class Functions
function types (func(T) T)
nil zero value panics
stored in variables and maps
Closures
capture by reference
loop-variable pitfall
Go 1.22 per-iteration fix
stateful iterators
Higher-Order Functions
filter, map, reduce patterns
function factories
standard library examples
Recursion
base case required
no tail-call optimization
mutually recursive functions
defer + Named Returns
closure modifies named return
error wrapping pattern
Method Values
bound receiver
same as function value
forward ref to Module 6
Alternative: draw this on paper, photo it, and link the image here.
Key Insights¶
The "aha moments" — the things that, once understood, made the rest clear. Be specific: "I finally understood X because Y" is more useful than "X makes sense".
- Closures capture references, not values: I finally understood why the loop-variable bug exists: the closure doesn't make a copy of
i— it holds a reference to the variable itself. By the time the closures run, the loop is done andiis at its terminal value. - Slices are three words, not one: The "photocopy" mental model clicked when I thought of a slice as a struct with three fields (pointer, len, cap). Copying a slice copies those three fields, not the underlying array. That's why element mutation is visible but append isn't.
- Add insights as you discover them
My Understanding¶
Explain the core concepts in your own words, as if teaching them to someone else. If you can't explain it simply, you don't understand it well enough yet.
Call-by-Value¶
Your explanation here
What I'm still unsure about: (e.g., when exactly does append allocate a new backing array vs reuse the existing one?)
Closures and Capture¶
Your explanation here
What I'm still unsure about: (e.g., how long does a captured variable live if the outer function has returned? Does the GC collect it?)
The (result, error) Convention¶
Your explanation here
What I'm still unsure about: (e.g., is there a way to make the compiler enforce that callers check the error?)
defer + Named Returns¶
Your explanation here
What I'm still unsure about: (e.g., what order do deferred closures run in if there are multiple in the same function?)
Connections to Other Topics¶
How does this module connect to things you already know?
| This module's concept | Connects to | How |
|---|---|---|
| defer + named returns | [[go/2. Control Flow]] | defer was introduced in Module 2; named returns reveal the full power of defer by allowing deferred closures to modify what the function returns |
| (result, error) return | [[go/8. Error Handling]] | The convention learned here (error last, nil for success, fmt.Errorf with %w) is the foundation of all error handling in Go |
| Closures in goroutines | [[go/9. Concurrency]] | Goroutines are almost always launched as closures; the loop-variable capture pitfall is especially dangerous in concurrent code where closures run in separate goroutines |
Questions That Arose¶
Log questions as they appear. Don't stop to answer them now — just capture them. Then move the serious ones to QUESTIONS.md.
- What happens to captured variables when the outer function returns? Are they moved to the heap? → added to QUESTIONS.md as Q001
- Can a deferred function itself defer another function? → might be answered experimentally
- What is the performance cost of closures vs plain function calls? → might be answered in the profiling module
Code Snippets Worth Remembering¶
Patterns, idioms, or examples that captured something important.
The error wrapping pattern with defer + named returns¶
func operation(arg T) (result R, err error) {
defer func() {
if err != nil {
err = fmt.Errorf("operation: %w", err)
}
}()
// any error returned here is automatically wrapped
return
}
Why I'm saving this: This is the cleanest way to ensure every error from a function carries the function's name as context. Used in production Go code to build rich error chains.
The function factory pattern¶
func multiplier(factor int) func(int) int {
return func(n int) int { return n * factor }
}
double := multiplier(2)
triple := multiplier(3)
Why I'm saving this: Factory functions that return closures are Go's lightweight substitute for objects when you only need one operation. The captured variable (factor) is the "field", the returned closure is the "method".
Spreading a slice into a variadic call¶
Why I'm saving this: Easy to forget the ... suffix at the call site when passing a slice to a variadic function. Without it, you'd get a compile error (wrong type).
What Tripped Me Up¶
Mistakes I made, misconceptions I had, things that confused me more than they should have. Being honest here helps you later.
- Loop-variable capture — I initially thought each closure captured a copy of the loop variable at the time of creation. The
4, 4, 4, 4output was a surprise. Now I remember: closures capture references. - append and call-by-value — I expected
append(s, val)inside a function to grow the caller's slice. It doesn't — the caller's slice header is unchanged. I need to either return the new slice or pass*[]int.
Summary in My Own Words¶
Write a 3–5 sentence summary of this entire module without looking at any notes. If you can't do this, you need more study time.
Write your summary here after completing the module.
Last updated: YYYY-MM-DD