Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Optional: traverse recursive data

Traverse a chain without consuming it by matching a borrow. Some(next) below binds next as &Box[links.Node[i64]], which can be passed where a reference to the node is expected.

pub class Node[T]:
    pub value: T
    pub next: Option[Box[Node[T]]]
import links

def total(node: &links.Node[i64]) -> Result[i64, OverflowError[i64]]:
    match &node.next:
        case Some(next):
            Ok(node.value + total(next)?)
        case Nothing:
            Ok(node.value)

def increment(node: &mut links.Node[i64]) -> Result[(), OverflowError[i64]]:
    node.value = node.value + 1
    match &mut node.next:
        case Some(next):
            return increment(next)
        case Nothing:
            pass
    Ok(())

def main() -> Result[(), AllocError | IoError | OverflowError[i64]]:
    mut chain = links.Node[i64](3, Some(Box(links.Node[i64](6, Nothing))?))
    print(total(&chain)?)?
    increment(&mut chain)?
    print(total(&chain)?)?
    print(chain.value)?
    Ok(())
9
11
4

match &mut value binds mutable payload references, allowing increment to update each node while its caller keeps the chain.

increment ends with a tail call through a reference borrowed from its parameter, so its stack does not grow. total adds after its recursive call returns, so it uses native stack space for every node.

A loop avoids that. Declare a reference binding with mut and assign it the next node. Such a binding may only be assigned a reference borrowed from itself, which next is: it comes from match &node.next.

class Node:
    value: i64
    next: Option[Box[Node]]

def total(head: &Node) -> Result[i64, OverflowError[i64]]:
    mut sum = 0
    mut node = head
    while True:
        sum = sum + node.value
        match &node.next:
            case Some(next):
                node = next
            case Nothing:
                break
    Ok(sum)

def increment(head: &mut Node) -> Result[(), OverflowError[i64]]:
    mut node = head
    while True:
        node.value = node.value + 1
        match &mut node.next:
            case Some(next):
                node = next
            case Nothing:
                break
    Ok(())

def main() -> Result[(), AllocError | IoError | OverflowError[i64]]:
    mut chain = Node(3, Some(Box(Node(6, Nothing))?))
    increment(&mut chain)?
    print(total(&chain)?)?
    Ok(())
11

The chain stays borrowed while node is used. The loop’s stack usage is independent of chain length.