Defer

Defer adalah mekanisme untuk menunda eksekusi fungsi hingga fungsi yang melingkupinya selesai. Defer sangat berguna untuk cleanup operations.

Contoh Masalah

Bagaimana cara:

  1. Memastikan resource dibersihkan
  2. Menangani cleanup operations
  3. Mengatur urutan eksekusi

Penyelesaian

package main

import (
    "fmt"
    "io"
    "os"
    "sync"
)

// 1. Basic file handling dengan defer
func writeToFile(filename string, content string) error {
    // Open file
    file, err := os.Create(filename)
    if err != nil {
        return err
    }
    defer file.Close() // Will be called when function returns

    // Write content
    _, err = io.WriteString(file, content)
    return err
}

// 2. Multiple defers
func multipleDefers() {
    fmt.Println("Start")
    defer fmt.Println("First defer")
    defer fmt.Println("Second defer")
    defer fmt.Println("Third defer")
    fmt.Println("End")
}

// 3. Defer dengan parameter evaluation
func parameterEvaluation() {
    i := 0
    defer fmt.Printf("Deferred i: %d\n", i)
    i++
    fmt.Printf("Final i: %d\n", i)
}

// 4. Defer dalam loop
func deferInLoop() {
    for i := 0; i < 3; i++ {
        defer fmt.Printf("Deferred %d\n", i)
    }
}

// 5. Custom cleanup dengan defer
type Resource struct {
    name string
    mu   sync.Mutex
}

func (r *Resource) Use() {
    r.mu.Lock()
    defer r.mu.Unlock()

    fmt.Printf("Using resource: %s\n", r.name)
    // Simulate work
    for i := 0; i < 3; i++ {
        fmt.Printf("Working with %s: step %d\n", r.name, i+1)
    }
}

// 6. Panic recovery dengan defer
func mayPanic() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Printf("Recovered from panic: %v\n", r)
        }
    }()

    panic("something went wrong")
}

// 7. Nested defer
func nestedDefer() {
    fmt.Println("Entering outer function")
    defer fmt.Println("Exiting outer function")

    func() {
        fmt.Println("Entering inner function")
        defer fmt.Println("Exiting inner function")
        fmt.Println("Inner function executing")
    }()

    fmt.Println("Outer function executing")
}

func main() {
    // Contoh 1: File handling
    fmt.Println("File Handling Example:")
    err := writeToFile("test.txt", "Hello, World!")
    if err != nil {
        fmt.Printf("Error writing file: %v\n", err)
    } else {
        fmt.Println("File written successfully")
    }

    // Contoh 2: Multiple defers
    fmt.Printf("\nMultiple Defers Example:\n")
    multipleDefers()

    // Contoh 3: Parameter evaluation
    fmt.Printf("\nParameter Evaluation Example:\n")
    parameterEvaluation()

    // Contoh 4: Defer in loop
    fmt.Printf("\nDefer in Loop Example:\n")
    deferInLoop()

    // Contoh 5: Resource cleanup
    fmt.Printf("\nResource Cleanup Example:\n")
    r := &Resource{name: "database"}
    r.Use()

    // Contoh 6: Panic recovery
    fmt.Printf("\nPanic Recovery Example:\n")
    mayPanic()

    // Contoh 7: Nested defer
    fmt.Printf("\nNested Defer Example:\n")
    nestedDefer()

    // Cleanup test file
    os.Remove("test.txt")
}

Penjelasan Kode

  1. Basic Defer

    • Delay execution
    • LIFO order
    • Function completion
  2. Common Uses

    • File handling
    • Lock/unlock
    • Resource cleanup
  3. Special Cases

    • Parameter evaluation
    • Nested defers
    • Panic recovery

Output

File Handling Example:
File written successfully

Multiple Defers Example:
Start
End
Third defer
Second defer
First defer

Parameter Evaluation Example:
Final i: 1
Deferred i: 0

Defer in Loop Example:
Deferred 2
Deferred 1
Deferred 0

Resource Cleanup Example:
Using resource: database
Working with database: step 1
Working with database: step 2
Working with database: step 3

Panic Recovery Example:
Recovered from panic: something went wrong

Nested Defer Example:
Entering outer function
Entering inner function
Inner function executing
Exiting inner function
Outer function executing
Exiting outer function

Tips

  • Gunakan defer untuk cleanup
  • Perhatikan urutan eksekusi
  • Evaluasi parameter saat defer
  • Hindari defer dalam loop
  • Defer untuk error handling