Rust Tuples Tutorial

In this Rust tutorial we learn the compound type tuple data container that allows us to store multiple values of different types.

We cover how to create a tuple, how to access its elements with dot notation and why we can't iterate over a tuple with a loop. We also learn how to destruct a tuple into separate variables.

Here's a table of contents of what you'll learn in this lesson:
(click on a link to skip to its section)

Let's jump right in.

What is a tuple

A tuple is a compound type data container, which means it can store multiple values of different types.

We don’t use a tuple as a collection, or drop-in replacement for an array. A tuple is actually a struct underneath, so we use it when we want something that’s less verbose than a struct.

How to create (initialize) a tuple

Rust provides us with three variations in syntax to initialize a tuple.

Syntax: initialize a tuple
// variation 1
let tuple_name = (value_1, value_2, ...);

// variation 2
let tuple_name:(data_type_1, data_type_2, ...) = (value_1, value_2, ...);

In the first variation, we allow Rust to infer the data type from the values of the tuple.

Example: initialize a tuple
fn main() {

    let mix = (10, 3.14, "Hello World");

}

In the example above, the compiler will automatically assign an int, float and string data type to the elements of the tuple.

In the second variation we explicitly specify the types for each value in the tuple.

Example: explicit type tuple initialization
fn main() {

    let mix:(i32, f64, &str) = (10, 3.14, "Hello World");

}

In the example above, we specify int32, float64 and string as the types in the tuple. Each value must correspond to its type, or the compiler will raise an error.

Note that the name and type list is separated by a colon. Also note that the types in the list are separated with a comma, not a semicolon.

How to access tuple values

Before we proceed, let’s see how to print the whole tuple to the console.

Example: print the entire tuple to the console
fn main() {

    let mix:(i32, f64, &str) = (10, 3.14, "Hello World");

    println!("{:?}", mix);

}

We simply specify the tuple name in the println macro. The :? between the curly braces will do what’s known as a pretty print variation, allowing us to see the whole tuple at once.

This helps us quickly see all the values in an tuple.

All tuple elements have a corresponding index number that can be used to access the element.

012
103.14Hello World

To access a specific element, we need to reference its corresponding index number with dot notation.

Dot notation is where we add a dot after the tuple name, followed by the index of the element we want to access.

Dot notation is a feature of structures, and because a tuple is technically a struct, dot notation is used to access its elements.

Example:
fn main() {

    let mix:(i32, f64, &str) = (10, 3.14, "Hello World");

    println!("{}", mix.2);

}

In the example above, we access the element at index number 2.

You may notice that we use the index number 2, but the third value in the tuple “Hello World” was printed to the console.

This is because any collection or array with an index, will always start at the number 0, not 1. This is true for almost all programming languages (lua tables start at 1 for example).

So, if we want to access an element, we just subtract one from its position and we have the correct index.

How to access tuple elements in a loop

Because a tuple is technically a struct, we cannot iterate over its elements in a loop.

If we want a data container that can be iterated over, it would be better to store our data into an array or a collection (like a HashMap ).

How to destruct a tuple

Rust allows us to destruct a tuple, which means we unpack the tuple’s values into separate variables.

Let’s look at the syntax to destruct a tuple.

Syntax: destruct a tuple
// tuple
let tuple_name = (value_1, value_2, ...);

// destruct
let (var_for_value_1, var_for_value_2, ...) = tuple_name;

We specify the names of the variables that will hold the tuple values between parentheses, separated by a comma. Then, we assign the tuple to the list of variables.

The compiler will take each value in the tuple and assign it to its corresponding variable.

Example: destruct a tuple
fn main() {

    let mix:(i32, f64, &str) = (10, 3.14, "Hello World");

    println!("Tuple: {:?}\n", mix);

    let (num, pi, msg) = mix;

    println!("Var num: {}", num);
    println!("Var pi:  {}", pi);
    println!("Var msg: {}", msg);

}

In the example above, we assign the value 10 to the variable num, the value 3.14 to the variable pi and the value “Hello World” to the variable message.

We can then use the variables as we normally would. In this case we only print them to the console.

Summary: Points to remember

  • A tuple is a data container that can store multiple different types of values.
  • A tuple isn’t technically like a collection or array, it’s simply a less verbose method of writing a struct.
  • Tuple values are accessed with dot notation where we separate the tuple name and the value index number with a dot operator.
  • Tuples cannot be iterated over like an array or collection.
  • We can destruct a tuple by assigning its values into separate variables.