Rust: tuple vs array
Tags: rust
Published: 2020-10-21 22:04:00

---
title: "Rust: tuple vs array"
published: true
tags: rust
canonical_url: https://nickymeuleman.netlify.app/garden/rust-tuple-array
---

Tuples group values with a variety of types.  
Arrays group values of a single type.  
They both have a fixed size.

While arrays are less flexible in content, they are more flexible in usage.

---

The array and the tuple are both _compound_ types, that means they can hold multiple values.
An array and a tuple are both groups of other values.

Tuples are enclosed by parentheses `()`.
Every element in it is separated by a comma `,`.

Arrays are enclosed by square braces `[]`.
Every element in it is separated by a comma `,`.

They are both fixed in size, they can't shrink or grow.
A [vector](https://doc.rust-lang.org/std/vec/struct.Vec.html) is a similar collection type that is allowed to change in size.

So far, they sound _very_ similar, with just some arbitrary syntax differentiating them.

## Types

For an array, every item in that group has to have the same type.
If a value in that array is of type `f64`, every item in that array _must_ be of type `f64`.

```rust
let arr = [1.0, 2.5, 3.14];
```

For tuples, items in that group can have different types.
All values in a tuple _can_ be the same type, but they can be different too.

```rust
let tup = (1, 2.5, "yummy pie");
```

### Annotating the types

The Rust compiler is smart and will try to figure out which types it's dealing with, that means explicit type declarations are not always needed.

For arrays, the type declaration consists of enclosing square brackets. Inside is the type of the elements followed by a semicolon `;`, and the length or the array.

```rust
let arr: [f64;3] = [1.0, 2.5, 3.14];
```

For tuples, the type declaration consists of enclosing parentheses. Inside are the types of each element, each one separated by a comma `,`.

```rust
let tup: (i32, f64, &str) = (1, 2.5, "yummy pie");
```

## Accessing information

### Element by index

Indexes for both tuples and arrays start at 0.
Tuples, somewhat surprisingly, use the `.` to access an element at a specific index.

```rust
let first_arr = arr[0]; // 1.0
let first_tup = tup.0; // 1
```

### Element by destructuring

```rust
let (tup_first, tup_second, tup_third) = tup;
let [arr_first, arr_second, arr_third] = arr;
println!("tup_first: {}, tup_second: {}, tup_third: {}", tup_first, tup_second, tup_third);
// tup_first: 1, tup_second: 2.5, tup_third: "yummy pie"
println!("arr_first: {}, arr_second: {}, arr_third: {}", arr_first, arr_second, arr_third);
// arr_first: 1.0, arr_second: 2.5, arr_third: 3.14
```

It's a lot more common to destructure tuples.
It's especially handy if a function returns 2 values in a tuple and you want to name each value individually.

```rust
fn num_and_double(num: i32) -> (i32, i32) {
    (num, num * 2)
}
let (lucky_num, double_lucky_num) = num_and_double(3);
```

### Length

An array has some metadata associated with it, like its length.
A tuple does not.
Tuples are essentialy structs with anonymous field names.

```rust
let arr_len = arr.len(); // 3
// let tup_len = tup.len(); // error
```

## Looping

Iterating over a tuple doesn't work.
For a tuple, each iteration could result in a different type, that doesn’t work.
Since arrays can only hold a single type, they don't have that limitation.

```rust
// for num in &tup {
//     println!("num: {}", num);
// }
// error

for num in &arr {
    println!("num: {}", num);
}
// num: 1.0
// num: 2.5
// num: 3.14
```

_Ok, fine. I'll iterate over a number range and access each item in the tuple via the dot synt_...NOPE  
Tuples can’t be dynamically indexed.

The compiler needs to be able to figure out what type every value is, indexing into it with a variable makes this impossible.
If the compiler doesn't know which index is being used, it can not figure out what type the value at that index is.

> Here’s an (slightly contrived) example of why you can’t do stuff like that in Rust:
>
> ```rust
> let myTuple = (1, 2, "false");
> let x = randomNumberGenerator();
> let y = myTuple.x;
> ```
>
> In this case, the compiler wouldn’t be able to figure out at compile-time what type y should be!
> Whereas with an array, you know (and the compiler knows) that indexing is always going to return the same type.
>
> <footer>
>
>
> &mdash; <a href="https://twitter.com/17cupsofcoffee">17cupsofcoffee</a>
>
> </footer>
>

```rust
let index = 2;

let arr_pi = arr[2]; // 3.14
let also_arr_pi = arr[index]; // 3.14

let tup_pie = tup.2; // "yummy pie"
// let also_tup_pie = tup.index; // error
```

## Code summary

```rust
fn main() {
    let tup = (1,2,3);
    let arr = [1,2,3];
    let index = 2;

    println!("Array: {:?}", arr[2]); // Array: 3
    println!("Array: {:?}", arr[index]); // Array: 3
    println!("Tuple: {:?}", tup.2); // Tuple: 3
    // println!("Tuple: {:?}", tup.index); // error

    for num in &arr {
        println!("num: {}", num);
    }
    // num: 1
    // num: 2
    // num: 3

    // for num in &tup {
    //     println!("num: {}", num);
    // }
    // error

    let (tup_first, tup_second, tup_third) = tup;
    let [arr_first, arr_second, arr_third] = arr;

    println!("tup_first: {}, tup_second: {}, tup_third: {}", tup_first, tup_second, tup_third);
    // tup_first: 1, tup_second: 2, tup_third: 3

    println!("arr_first: {}, arr_second: {}, arr_third: {}", arr_first, arr_second, arr_third);
    // arr_first: 1, arr_second: 2, arr_third: 3

    // tup.len() // error
    arr.len() // 3
}
```