Returning and unpacking tuples
A tuple groups values with different types. Write (value,) for one component;
parentheses without a comma simply group an expression. Function signatures may
spell a tuple as (i64, str) or tuple[i64, str]. Unpacking transfers owned
components, and _ discards a component. Indices must be integer literals; as
with lists, a negative index counts from the end, so pair[-1] is the last
component.
def measurement() -> (i64, str):
(42, "cm")
def main() -> Result[(), IoError]:
value, unit = measurement()
print(value)?
print(unit)?
print((3, "three"))?
Ok(())
42
cm
(3, "three")
Creating (a, b) does not allocate a tuple, so it needs no ?. Operations that
produce its components, such as the list construction below, can still fail.
Nested tuples can be unpacked in one statement. Match each tuple’s shape,
using _ for a component you do not need:
def main() -> Result[(), IoError | OverflowError[i64]]:
((x, y), label) = ((3, 4), "point")
print(label, x + y)?
Ok(())
point 7
Tuples of numbers, strings, or nested tuples of those can be compared. The first
differing component decides the result, just as in sort(). Comparisons leave
both values available:
def main() -> Result[(), IoError]:
first = (1, "apple")
second = (1, "pear")
print(first < second, first <= first)?
print(first, second)?
Ok(())
True True
(1, "apple") (1, "pear")
Tuple float components follow sorting’s total order: -0.0 precedes 0.0, and
NaNs come last. This differs from scalar float comparison; tuple equality still
uses the components’ ordinary equality.
Distinct tuple components can be borrowed and read independently. The borrow below protects component 1 while component 0 remains readable:
def main() -> Result[(), AllocError | IoError]:
mut pair = (1, [2]?)
items = &mut pair[1]
first = pair[0]
print(first)?
print(pair[0])?
items.append(3)?
print(pair)?
Ok(())
1
1
(1, [2, 3])
Copyable components can be changed through mutable references too. A saved copy has its own inline storage:
def main() -> Result[(), IoError]:
mut pair = (1, 2)
saved = pair
first = &mut pair[0]
*first = 5
print(pair)?
print(saved)?
Ok(())
(5, 2)
(1, 2)
Use a reference for the write; direct pair[0] = 5 is not supported.
Reading an exclusively borrowed component is rejected:
def main() -> Result[(), AllocError | IoError]:
mut pair = (1, [2]?)
items = &mut pair[1]
print(pair[1])?
items.append(3)?
Ok(())
conflicting borrow: cannot read or borrow `pair[1]` while it is exclusively borrowed