Start learning free

LESSON 267 OF 679 · TUPLES, SORTING & BUILT-INS

Tuples in Rust: Grouping and Unpacking Values

Lesson Read the full explanation

TL ; DR:

A tuple keeps a few values together, like a movie's title and year. Read them with .0 and .1, or unpack them into variables.


let movie = ("Frozen", 2013);     // a tuple

println!("{}", movie.0);          // Frozen

println!("{}", movie.1);          // 2013

let (title, year) = movie;        // unpacking

println!("{} {}", title, year);   // Frozen 2013


Full lesson:

Some values belong together. A movie has a title and a year. A point has an x and a y. A tuple keeps a few values like these in one variable.

  • ("Frozen", 2013) makes a tuple. Its type is (&str, i32).
  • movie.0 is the first value, "Frozen". movie.1 is the second, 2013. Use a dot, not square brackets.
  • {:?} prints a whole tuple, as it prints a vector: ("Frozen", 2013).

let (title, year) = movie; unpacks the tuple into two new variables. It works like for (name, points) in &scores.

A function can return a tuple. Its return type is the tuple's type, like (i32, i32). Then return (a, b); builds it.

A tuple made with let can't be changed, like any Rust value. With let mut, movie.1 = 2014 works. Still, a tuple never gets more values, and its types stay fixed.


Your task

Rex the dog went for a long walk. pet holds his name and his age.

First, make split_time return its tuple: the whole hours and the minutes left.

Then unpack pet into name and age.

Last, call split_time(135). Unpack its result into hours and mins.

The code already prints the three lines.

Expected output:

Rex
Rex is 4
Rex walked 2 h 15 min
STEP 1 OF 3
    Ctrl + Enter to check

    RUST · TUPLES, SORTING & BUILT-INS

    Tuples in Rust, explained

    What a tuple is

    Some values belong together: a movie has a title and a year, a point has an x and a y. A tuple keeps a few values like these in one variable. The values can have different types, and the number of values is part of the tuple's type.

    let movie = ("Frozen", 2013);
    println!("{}", movie.0);
    println!("{}", movie.1);
    println!("{:?}", movie);
    Frozen
    2013
    ("Frozen", 2013)

    The type of movie is (&str, i32). You read a value with a dot and its position, .0 for the first and .1 for the second. Square brackets don't work on a tuple, because the positions are part of the type, not numbers computed at run time. The {:?} format prints the whole tuple at once, the way it prints a vector.

    Unpacking

    A let with a pattern on the left takes a tuple apart into separate variables:

    let (title, year) = movie;
    println!("{} {}", title, year);
    Frozen 2013

    The names go in the same order as the values. This is the same pattern a loop uses in for (name, points) in &scores: each item is a tuple, and the loop unpacks it for you.

    Returning two values

    Rust functions return one value, so a function that needs to give back two returns a tuple. The return type is the tuple's type, for example (i32, i32), and return (a, b); builds the tuple. The caller unpacks the result with the same let (a, b) = ... pattern.

    Changing a tuple

    As with any Rust value, a tuple made with plain let can't be changed. Assigning to one of its fields is a compile error:

    error[E0594]: cannot assign to `movie.1`, as `movie` is not declared as mutable

    With let mut movie, the assignment movie.1 = 2014; works. Even then, a tuple never gets more values, and each position keeps its type. If you need a collection that grows, use a vector.

    The exercise, step by step

    The task asks for three things, and the code already prints each result.

    1. Return the tuple from split_time. The whole hours are minutes / 60 and the minutes left are minutes % 60. Integer division drops the fraction, so 135 gives 2 hours and 15 minutes.
    2. Unpack pet into name and age, in the order the tuple holds them.
    3. Call split_time(135) and unpack its result into hours and mins the same way.
    fn split_time(minutes: i32) -> (i32, i32) {
        return (minutes / 60, minutes % 60);
    }
    
    fn main_function() {
        let pet = ("Rex", 4);
        println!("{}", pet.0);
    
        let (name, age) = pet;
        println!("{} is {}", name, age);
    
        let (hours, mins) = split_time(135);
        println!("{} walked {} h {} min", name, hours, mins);
    }

    Run, it prints:

    Rex
    Rex is 4
    Rex walked 2 h 15 min

    Common mistakes

    • Square brackets. movie[0] is an error. Use movie.0.
    • Wrong number of names. let (a, b, c) = movie; doesn't compile, because the pattern must have as many parts as the tuple has values.
    • Wrong order. The names follow the order of the values, so let (year, title) = movie; would put the title in year.
    • Forgetting the type of a returned tuple. A function that returns two numbers needs -> (i32, i32) in its signature, not just -> i32.

    Tuples are used throughout this chapter: a vector can hold tuples, a sort can compare their fields, and loops can unpack them as they go.

    Key takeaways

    • A tuple groups a fixed number of values, possibly of different types, in one variable.
    • Read a value with .0, .1 and so on, or unpack all of them with let (a, b) = tuple;.
    • A function returns several values by returning a tuple, and its return type is the tuple's type.
    • A tuple needs let mut to change a field, and it never changes size or types.
    Keep going with Rust500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free