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}Generic functions
Section titled “Generic functions”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 intlet s = first(["a", "b"])T is stringlet swapped = swap((1, "one"))A is int, B is stringType arguments are required when inference has nothing to work with:
let nums = Slice.new<int>()no elements to infer T fromlet counts = Map.new<string, int>()no entries to infer K and V fromWrite permission in parameters
Section titled “Write permission in parameters”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 itemsfn sort(items: mut Slice<int>)can write to itemsA 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 mutParameters 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
Section titled “Lambdas”Lambdas are anonymous inline functions.
let double = |x: int| x * 2let sum = |a: int, b: int| a + blet produce_int = || 42Lambda 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 = 3let scale = |x: int| x * multiplierIterators
Section titled “Iterators”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)}