← Go EnglishChapter 05 of 13

Functions

## Learning Objectives - Define and call functions - Return multiple values - Use variadic functions - Understand closures - Pass functions as values - Use panic and recover ## Basic Functions ### Declaration ```go func greet(name string) { fmt.Println("Hello,", name) } func main() { greet("Alice") // Hello, Alice } ``` ### With Return Value ```go func add(a, b int) int { return a + b } func main() { result := add(3, 5) fmt.Println(result) // 8 } ``` ### Multiple Parameters ```go func greet(firstName, lastName string) { fmt.Printf("Hello, %s %s\n", firstName, lastName) } ``` ## Multiple Return Values ### Basic Multiple Returns ```go func divide(a, b float64) (float64, float64) { quotient := a / b remainder := a - quotient*b return quotient, remainder } func main() { q, r := divide(10, 3) fmt.Printf("Quotient: %.2f, Remainder: %.2f\n", q, r) } ``` ### Named Return Values ```go func rectangleProperties(width, height float64) (area, perimeter float64) { area = width * height perimeter = 2 * (width + height) return // Naked return } ``` ### Ignore Return Values ```go quotient, _ := divide(10, 3) // Ignore remainder ``` ## Error Handling ### Returning Errors ```go func safeDivide(a, b float64) (float64, error)) { if b == 0 { return 0, errors.New("division by zero") } return a / b, nil } func main() { result, err := safeDivide(10, 0) if err != nil { fmt.Println("Error:", err) return } fmt.Println("Result:", result) } ``` ### Custom Error Types ```go type DivisionError struct { Dividend float64 Divisor float64 } func (e *DivisionError) Error() string { return fmt.Sprintf("cannot divide %.2f by zero", e.Dividend) } func safeDivide(a, b float64) (float64, error) { if b == 0 { return 0, &DivisionError{Dividend: a, Divisor: b} } return a / b, nil } ``` ## Variadic Functions ### Basic Variadic ```go func sum(nums ...int) int { total := 0 for _, n := range nums { total += n } return total } func main() { fmt.Println(sum(1, 2, 3)) // 6 fmt.Println(sum(1, 2, 3, 4, 5)) // 15 fmt.Println(sum()) // 0 } ``` ### Spread Operator ```go nums := []int{1, 2, 3, 4, 5} fmt.Println(sum(nums...)) // 15 ``` ### Multiple Variadic ```go func concat(separator string, values ...string) string { result := "" for i, v := range values { if i > 0 { result += separator } result += v } return result } func main() { fmt.Println(concat("-", "a", "b", "c")) // a-b-c } ``` ## Closures ### Basic Closure ```go func main() { add := func(a, b int) int { return a + b } fmt.Println(add(3, 5)) // 8 } ``` ### Closure with State ```go func counter() func() int { count := 0 return func() int { count++ return count } } func main() { next := counter() fmt.Println(next()) // 1 fmt.Println(next()) // 2 fmt.Println(next()) // 3 } ``` ### Closure for Caching ```go func memoize(f func(int) int) func(int) int { cache := make(map[int]int) return func(n int) int { if result, ok := cache[n]; ok { return result } result = f(n) cache[n] = result return result } } ``` ## Functions as Values ### Pass Function as Argument ```go func apply(nums []int, fn func(int) int) []int { result := make([]int, len(nums)) for i, n := range nums { result[i] = fn(n) } return result } func main() { nums := []int{1, 2, 3, 4, 5} doubled := apply(nums, func(n int) int { return n * 2 }) fmt.Println(doubled) // [2 4 6 8 10] } ``` ### Return Function ```go func multiplier(factor int) func(int) int { return func(n int) int { return n * factor } } func main() { double := multiplier(2) triple := multiplier(3) fmt.Println(double(5)) // 10 fmt.Println(triple(5)) // 15 } ``` ## Anonymous Functions ### IIFE (Immediately Invoked) ```go result := func() int { sum := 0 for i := 1; i <= 10; i++ { sum += i } return sum }() fmt.Println(result) // 55 ``` ### Named Parameters ```go func operate(a, b int, op func(int, int) int) int { return op(a, b) } func main() { result := operate(10, 5, func(x, y int) int { return x + y }) fmt.Println(result) // 15 } ``` ## Recursion ### Basic Recursion ```go func factorial(n int) int { if n <= 1 { return 1 } return n * factorial(n-1) } func main() { fmt.Println(factorial(5)) // 120 } ``` ### Fibonacci Recursive ```go func fibonacci(n int) int { if n <= 1 { return n } return fibonacci(n-1) + fibonacci(n-2) } ``` ## Methods ### Value Receiver ```go type Rectangle struct { Width, Height float64 } func (r Rectangle) Area() float64 { return r.Width * r.Height } func main() { r := Rectangle{Width: 10, Height: 5} fmt.Println(r.Area()) // 50 } ``` ### Pointer Receiver ```go func (r *Rectangle) Scale(factor float64) { r.Width *= factor r.Height *= factor } func main() { r := Rectangle{Width: 10, Height: 5} r.Scale(2) fmt.Println(r.Width, r.Height) // 20 10 } ``` ## panic and recover ### panic ```go func criticalSection() { defer fmt.Println("Cleanup") panic("Something went wrong!") fmt.Println("This won't print") } func main() { criticalSection() fmt.Println("This won't print either") } ``` ### recover ```go func safeCall() { defer func() { if r := recover(); r != nil { fmt.Println("Recovered from:", r) } }() panic("Something went wrong!") } func main() { safeCall() fmt.Println("Program continues...") } ``` ### When to Use panic - Reserved for truly unrecoverable situations - Programming errors (e.g., nil pointer dereference) - Not for expected error conditions (use error returns) ## Summary - Functions declared with `func` keyword - Multiple return values for error handling - Variadic functions accept variable arguments with `...` - Closures are functions that capture their environment - Functions are first-class citizens (can be passed as values) - Methods are functions with receiver parameters - panic/recover for exceptional situations, not normal errors

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →