Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I destructure a tuple so that the bindings are mutable?

Tags:

rust

If I have the following struct:

struct MyStruct { tuple: (i32, i32) };

And the following function:

// This will not compile
fn function(&mut struct: MyStruct) {
    let (val1, val2) = struct.tuple;
    val1 = 1;
    val2 = 2;
}

How do I borrow val1 and val2 as mutable so when I reassign them the changes appear in the original struct?

like image 541
euclio Avatar asked Jul 23 '15 18:07

euclio


People also ask

Are tuples mutable in Rust?

In Rust, a tuple is immutable, which means we cannot change its elements once it is created.

What Cannot be Destructured in Rust?

Destructuring structs and tuples is infallible. However, enums can also be destructured, using the if let , while let , and match language constructs.


2 Answers

You've got a few problems:

  • You've put the &mut in the wrong place; &mut is part of the type, not the argument (unless you're destructuring the argument, which you aren't).

  • You can't call the argument struct, because that's a keyword.

  • You can't assign to a mutable reference with straight assignment.

So, with those in mind, here's a working solution:

#[derive(Debug)]
struct MyStruct {
    tuple: (i32, i32),
}

fn function(s: &mut MyStruct) {
    let (ref mut val1, ref mut val2) = s.tuple;
    *val1 = 1;
    *val2 = 2;
}

fn main() {
    let mut s = MyStruct { tuple: (0, 0) };
    function(&mut s);
    println!("{:?}", s);
}

The key here is that ref in a pattern binds by-reference; combining that with mut gives you a mutable reference. Specifically, it gives you a pair of &mut i32s. Since these are references, you have to de-reference them in order to assign through them (otherwise, you'd be trying to re-assign the reference itself).

like image 108
DK. Avatar answered Oct 23 '22 18:10

DK.


You have two slightly different questions.

You can create a mutable bind by saying mut twice:

fn main() {
    let a = (1, 2);
    let (mut b, mut c) = a;
    b += 1;
    c += 2;

    println!("{}, {}", b, c);
}

But to have it change in the original tuple, you need a mutable reference into that tuple:

fn main() {
    let mut a = (1, 2);

    {
        let (ref mut b, ref mut c) = a;
        *b += 1;
        *c += 2;
        // Let mutable borrows end
    }

    println!("{:?}", a);
}
like image 45
Shepmaster Avatar answered Oct 23 '22 17:10

Shepmaster