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

Build recursive data

Chains and trees contain values of their own type. A directly embedded value would have no finite size, so put the recursive field in a Box or collection. A box owns one value on the heap.

This chain ends with Empty. Each Link owns a value and a box holding the rest of the chain:

enum Chain[T]:
    Empty
    Link(T, Box[Chain[T]])

def total(chain: Chain[i64]) -> Result[i64, OverflowError[i64]]:
    mut remaining = chain
    mut answer = 0
    while True:
        match remaining:
            case Chain.Empty:
                break
            case Chain.Link(value, rest):
                answer = answer + value
                remaining = rest
    Ok(answer)

def main() -> Result[(), AllocError | IoError | OverflowError[i64]]:
    mut chain = Chain[i64].Empty
    for value in range(1, 4):
        chain = Chain[i64].Link(value, Box(chain)?)
    print(total(chain)?)?
    Ok(())
6

Box(value) moves the value onto the heap and returns an allocation result. Constructing the Link itself allocates nothing.

When a value of type T is required, a Box[T] moves its content out and frees the box, without allocating. Here, remaining = rest expects Chain[i64], so it unboxes rest. The conversion also works for arguments, returns, annotated bindings, constructor fields, and collection elements. total consumes its chain; the caller cannot use it afterward.

A boxed class’s fields and methods are reached as b.field and b.method(), and where a function expects &T, you can pass a &Box[T]. Where no type is required, a box stays a box: other = b moves the box itself. Operators and conditions do not convert either. Write *b there to move the content out, or &*b and &mut *b to borrow it.

Without the box, the compiler rejects the declaration:

enum Chain:
    Empty
    Link(i64, Chain)

def main() -> ():
    pass
`Chain` contains itself and would have infinite size; store the recursive field in a `Box`, list, set, or dict