Loading...
Loading...

Go Functions Tutorial

Functions are fundamental building blocks in Go that encapsulate reusable code. They support parameters, return values, and can be passed around like other values, enabling powerful programming patterns and abstractions.

1. Function Basics

Functions in Go are declared with the func keyword and can have parameters and return values.

// Basic function
func greet(name string) {
    fmt.Println("Hello,", name)
}

// Function with return value
func add(a, b int) int {
    return a + b
}

// Multiple return values
func divide(a, b float64) (float64, error) {
    if b == 0.0 {
        return 0.0, errors.New("division by zero")
    }
    return a / b, nil
}

// Calling functions by it's function name
greet("Alice")
sum := add(5, 3)
result, err := divide(10.0, 2.0)

Key Characteristics:

  • Parameters and return types are declared after the name
  • Functions can return multiple values (commonly used for errors)
  • Functions are first-class citizens (can be assigned to variables)
  • Go supports variadic functions (accepting variable number of args)

Function Basics Quiz

How does Go handle multiple return values?

  • They must be wrapped in a struct
  • They are declared in parentheses after the parameters
  • Only one return value is allowed

2. Advanced Features

Go provides several powerful function features for flexible programming.

// Named return values
func calc(a, b int) (sum int, product int) {
    sum = a + b
    product = a * b
    return // naked return (uses named values)
}

// Variadic functions
func average(nums ...float64) float64 {
    total := 0.0
    for _, num := range nums {
        total += num
    }
    return total / float64(len(nums))
}

// Function as a type
type Operation func(int, int) int

func compute(a, b int, op Operation) int {
    return op(a, b)
}

// Anonymous functions
func() {
    fmt.Println("Immediately invoked function")
}()

Advanced Capabilities:

  • Named return values for documentation and clarity
  • Variadic parameters with ... syntax
  • Function types for passing functions as arguments
  • Anonymous functions (closures) for inline use

Advanced Features Quiz

What's the purpose of named return values?

  • They make returns optional
  • They document the return values and enable naked returns
  • They allow returning more values

3. Closures

Go functions can form closures, capturing variables from their surrounding scope.

// Simple closure
func counter() func() int {
    i := 0
    return func() int {
        i++
        return i
    }
}

// Practical closure example
func makeGreeter(prefix string) func(string) {
    return func(name string) {
        fmt.Println(prefix, name)
    }
}

// Using closures
next := counter()
fmt.Println(next()) // 1
fmt.Println(next()) // 2

greet := makeGreeter("Welcome")
greet("Alice") // Welcome Alice

Closure Characteristics:

  • Functions can reference variables from enclosing scopes
  • Captured variables persist between calls
  • Useful for creating specialized functions
  • Common in middleware and iterator patterns

Closures Quiz

What happens to closure variables between calls?

  • They are reset each time
  • They persist their state
  • They become global variables

4. Defer, Panic, and Recover

Go provides special control flow mechanisms for functions.

// Defer statement
func readFile(filename string) error {
    f, err := os.Open(filename)
    if err != nil {
        return err
    }
    defer f.Close() // executes when function exits
    
    // Process file
    return nil
}

// Panic and recover
func safeDivide(a, b int) (result int, err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("runtime error: %v", r)
        }
    }()
    
    if b == 0 {
        panic("division by zero")
    }
    return a / b, nil
}

Control Flow Features:

  • defer schedules calls when the function exits
  • panic stops normal execution and begins panicking
  • recover regains control of a panicking goroutine
  • Deferred functions run in LIFO order

Control Flow Quiz

When do deferred functions execute?

  • Immediately after declaration
  • When the surrounding function returns
  • At program termination

5. Methods and Receivers

Go methods are functions with a receiver that operate on types.

// Method with value receiver
type Circle struct {
    Radius float64
}

func (c Circle) Area() float64 {
    return math.Pi * c.Radius * c.Radius
}

// Method with pointer receiver
func (c *Circle) Scale(factor float64) {
    c.Radius *= factor
}

// Using methods
c := Circle{Radius: 5}
area := c.Area()
c.Scale(2)

// Non-struct receivers
type MyInt int

func (m MyInt) IsEven() bool {
    return m%2 == 0
}

Method Features:

  • Value receivers operate on copies (don't modify original)
  • Pointer receivers can modify the original value
  • Methods can be defined on any type in your package
  • Go automatically converts between values and pointers when calling methods

Methods Quiz

When should you use a pointer receiver?

  • For all methods
  • When the method needs to modify the receiver
  • Only with large structs

6. Common Function Patterns

Idiomatic Go uses several standard function patterns.

// Middleware pattern
func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        log.Println(r.Method, r.URL.Path)
        next.ServeHTTP(w, r)
    })
}

// Constructor function
func NewUser(name string, age int) *User {
    return &User{
        Name: name,
        Age:  age,
    }
}

// Option pattern for flexible configuration
type ServerOptions struct {
    Port    int
    Timeout time.Duration
}

type Option func(*ServerOptions)

func WithPort(port int) Option {
    return func(o *ServerOptions) {
        o.Port = port
    }
}

func NewServer(opts ...Option) *Server {
    options := &ServerOptions{Port: 8080, Timeout: 30 * time.Second}
    for _, opt := range opts {
        opt(options)
    }
    // Create server with options
}

Practical Patterns:

  • Middleware for wrapping functionality
  • Constructor functions for initialization
  • Option pattern for flexible configuration
  • Higher-order functions for abstraction
  • Worker pools using function channels

Patterns Quiz

What's the main benefit of the Option pattern?

  • Better performance
  • Flexible configuration with readable code
  • Automatic documentation

7. Performance Tips

Understanding function performance characteristics helps write efficient Go code.

// Inlining small functions
func add1(x int) int { return x + 1 } // Likely inlined

// Avoiding heap allocations
func process(data []byte) {
    // Work with slice (no copy if not escaped)
}

// Reducing interface conversions
type Processor interface {
    Process()
}

type myProcessor struct{}

func (p myProcessor) Process() {}

func useProcessor(p Processor) {
    p.Process()
}

// Using sync.Pool for heavy allocations
var bufferPool = sync.Pool{
    New: func() interface{} {
        return bytes.NewBuffer(make([]byte, 0, 1024))
    },
}

Optimization Tips:

  • Small functions may be inlined by the compiler
  • Minimize allocations in hot paths
  • Be mindful of interface conversion costs
  • Consider sync.Pool for frequently allocated objects
  • Use benchmarks to validate optimizations

Performance Quiz

When might function inlining occur?

  • Only with //go:inline directives
  • For small, simple functions
  • Only in test files
0 Interaction
0 Views
Views
0 Likes
×
×
×
🍪 CookieConsent@Ptutorials:~

Welcome to Ptutorials

$ Allow cookies on this site ? (y/n)

top-home