Skip to content

Functions

A function has a name, parameters with type annotations, an optional return type, and a body.

fn add(a: int, b: int) -> int {
a + b
}
fn greet(name: string) {
fmt.Println(f"Hello, {name}")
}

Parameter types are required. The return type can be omitted, in which case it defaults to ().

The last expression in the function body is the return value. Use return for early exits.

fn first_positive(nums: Slice<int>) -> Option<int> {
for n in nums {
if n > 0 {
return Some(n)early exit
}
}
Nonereturned automatically
}

Type parameters appear in angle brackets after the function name.

fn first<T>(xs: Slice<T>) -> Option<T> {
xs.get(0)
}
fn swap<A, B>(pair: (A, B)) -> (B, A) {
(pair.1, pair.0)
}

The compiler infers type arguments at call sites:

let n = first([1, 2, 3])T is int
let s = first(["a", "b"])T is string
let swapped = swap((1, "one"))A is int, B is string

Type arguments are required when inference has nothing to work with:

let nums = Slice.new<int>()no elements to infer T from
let counts = Map.new<string, int>()no entries to infer K and V from

A parameter’s type carries write permission, signaling whether it can write through to the caller’s data.

fn total(items: Slice<int>) -> intcannot write to items
fn sort(items: mut Slice<int>)can write to items

A writable value fits a read-only parameter, but never the reverse.

let mut nums = [3, 1, 2]
sort(nums)permission matches
let nums = [3, 1, 2]
sort(nums)error: nums was declared without mut

Parameters themselves are immutable. To write to one, reassign it with let mut.

fn digits(n: int) -> int {
let mut n = nreassignment
let mut count = 1
while n >= 10 {
n /= 10
count += 1
}
count
}

Lambdas are anonymous inline functions.

let double = |x: int| x * 2
let sum = |a: int, b: int| a + b
let produce_int = || 42

Lambda parameter types can be omitted when inferable:

let doubled = [1, 2, 3].map(|x| x * 2)

A block body allows multiple statements:

let process = |x: int| {
let y = x * 2
y + 1
}

Lambdas can capture variables from the enclosing scope:

let multiplier = 3
let scale = |x: int| x * multiplier

A for loop accepts any function returning Go’s iter.Seq<T>. To write one, return a lambda that takes a yield function. Call yield once per element, and return as soon as yield gives back false:

import "go:iter"
fn count_up(n: int) -> iter.Seq<int> {
|yield: fn(int) -> bool| {
for i in 0..n {
if !yield(i) { return }
}
}
}
for i in count_up(1000) {
if i == 3 { break }ends the iterator
fmt.Println(i)
}