Go BasicsJanuary 29, 2025

Functions in Go - Complete Guide

Learn how to create and use functions in Go. Understand function syntax, parameters, return values, and best practices.

Author: Sushil Kumar

golangfunctionsmethodsprogramming

Functions in Go - Complete Guide

Functions are the building blocks of Go programs. They let you write code once and use it many times. Learning functions is essential - let's master them together!

What is a Function?

A function is a block of code that performs a specific task. You give it input, it does something, and optionally returns output.

Basic Function Syntax

func functionName() {
    // Code here
}

Simple Example

package main
 
import "fmt"
 
func greet() {
    fmt.Println("Hello, World!")
}
 
func main() {
    greet()  // Call the function
}

Functions with Parameters

Functions can take input values called parameters:

func greet(name string) {
    fmt.Printf("Hello, %s!\n", name)
}
 
func main() {
    greet("John")  // Hello, John!
    greet("Jane")  // Hello, Jane!
}

Multiple Parameters

func add(a int, b int) {
    sum := a + b
    fmt.Println(sum)
}
 
// Shorter syntax (same types)
func multiply(a, b int) {
    product := a * b
    fmt.Println(product)
}

Functions with Return Values

Functions can return values:

func add(a int, b int) int {
    return a + b
}
 
func main() {
    result := add(5, 3)
    fmt.Println(result)  // 8
}

Multiple Return Values

Go can return multiple values - this is very useful!

func divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, fmt.Errorf("cannot divide by zero")
    }
    return a / b, nil
}
 
func main() {
    result, err := divide(10, 2)
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println(result)  // 5
    }
}

Named Return Values

You can name return values:

func calculate(a, b int) (sum int, product int) {
    sum = a + b
    product = a * b
    return  // Naked return - uses named values
}
 
func main() {
    s, p := calculate(3, 4)
    fmt.Println(s, p)  // 7 12
}

Variadic Functions

Functions that accept any number of arguments:

func sum(numbers ...int) int {
    total := 0
    for _, num := range numbers {
        total += num
    }
    return total
}
 
func main() {
    fmt.Println(sum(1, 2, 3))        // 6
    fmt.Println(sum(1, 2, 3, 4, 5))  // 15
}

Function as Values

Functions are first-class citizens in Go - you can assign them to variables:

func add(a, b int) int {
    return a + b
}
 
func main() {
    operation := add
    result := operation(5, 3)
    fmt.Println(result)  // 8
}

Anonymous Functions

Functions without names:

func main() {
    greet := func(name string) {
        fmt.Printf("Hello, %s!\n", name)
    }
    
    greet("John")  // Hello, John!
}

Immediately Invoked Functions

func main() {
    func() {
        fmt.Println("This runs immediately!")
    }()
}

Closures

Functions that capture variables from outer scope:

func counter() func() int {
    count := 0
    return func() int {
        count++
        return count
    }
}
 
func main() {
    c := counter()
    fmt.Println(c())  // 1
    fmt.Println(c())  // 2
    fmt.Println(c())  // 3
}

Methods (Functions on Types)

Go doesn't have classes, but you can add methods to types:

type Rectangle struct {
    width  float64
    height float64
}
 
// Method on Rectangle
func (r Rectangle) area() float64 {
    return r.width * r.height
}
 
func main() {
    rect := Rectangle{width: 10, height: 5}
    fmt.Println(rect.area())  // 50
}

Pointer Receivers

Use pointers to modify the original value:

func (r *Rectangle) scale(factor float64) {
    r.width *= factor
    r.height *= factor
}
 
func main() {
    rect := Rectangle{width: 10, height: 5}
    rect.scale(2)
    fmt.Println(rect.width)  // 20
}

Defer Statement

Defer runs a function after the surrounding function returns:

func main() {
    defer fmt.Println("This runs last")
    fmt.Println("This runs first")
    fmt.Println("This runs second")
}
// Output:
// This runs first
// This runs second
// This runs last

Common use case - closing files:

file, err := os.Open("file.txt")
if err != nil {
    return err
}
defer file.Close()  // Always closes, even if error occurs

Visual Explanation: Function Flow

Here's how functions work:

Function Call Flow:
┌─────────────────────────────┐
│ main()                      │
│   │                         │
│   ├─► greet("John")        │
│   │     │                   │
│   │     ▼                   │
│   │   ┌──────────────┐     │
│   │   │ greet()      │     │
│   │   │ executes     │     │
│   │   └──────┬───────┘     │
│   │         │              │
│   │         ▼              │
│   │   Returns control      │
│   │                         │
│   └─► Continue in main()   │
└─────────────────────────────┘

Frequently Asked Questions (FAQ)

Q1: What's the difference between a function and a method?

A:

  • Function - Standalone, not attached to a type
  • Method - Attached to a type (has a receiver)

Methods are functions with receivers!

Q2: Can functions return multiple values?

A: Yes! Go supports multiple return values, which is very common:

func getData() (string, int, error) {
    return "name", 25, nil
}

Q3: What's a variadic function?

A: A function that accepts any number of arguments:

func sum(numbers ...int) int {
    // numbers is a slice
}

Q4: When should I use a pointer receiver?

A: Use pointer receivers when:

  • You need to modify the value
  • The struct is large (for efficiency)
  • You want to share the same instance

Q5: What does defer do?

A: Defer schedules a function to run after the current function returns. It's great for cleanup tasks like closing files.

Q6: Can I pass functions as parameters?

A: Yes! Functions are first-class in Go:

func apply(fn func(int) int, x int) int {
    return fn(x)
}

Q7: What's a closure?

A: A function that captures variables from its outer scope. The inner function "closes over" the outer variables.

Q8: Can I have optional parameters?

A: Not directly, but you can use variadic parameters or structs with default values to achieve similar results.

Q9: What's the difference between value and pointer receivers?

A:

  • Value receiver - Works on a copy, doesn't modify original
  • Pointer receiver - Works on original, can modify it

Q10: How do I handle errors in functions?

A: Return error as the last return value:

func doSomething() (result string, err error) {
    // If error occurs:
    return "", fmt.Errorf("something went wrong")
    // If success:
    return "success", nil
}

Next Steps

Now that you understand functions, here's what to learn next:

Functions are essential in Go. Practice writing different types of functions to get comfortable!