Lukas Kalbertodt
Lukas Kalbertodt

Reputation: 88736

Destructure immutable reference and bind mutably in parameter list

I want to destructure a reference to a Copy-type and bind the resulting value mutably. Note: yes, I want to create a copy of the given argument and mutate that copy. This works:

fn foo(a: &u64) {
    let mut a = *a;
    mutate(&mut a);
}

But I want to do it via destructuring in the argument list. When I just destructure like this:

fn foo(&a: &u64) {
    mutate(&mut a);
}

Rust (understandably) complains:

<anon>:3:17: 3:18 error: cannot borrow immutable local variable `a` as mutable
<anon>:3     mutate(&mut a);
                         ^
<anon>:1:9: 1:10 help: to make the local variable mutable, use `mut` as shown:
<anon>:  fn foo(&mut a: &u64) {

But the solution the compiler suggests does not work!

<anon>:1:8: 1:14 error: mismatched types:
 expected `&u64`,
    found `&mut _`
(values differ in mutability) [E0308]
<anon>:1 fn foo(&mut a: &u64) {
                ^~~~~~

How to do what I want?

Upvotes: 3

Views: 290

Answers (2)

user395760
user395760

Reputation:

I don't think you can do that. While patterns can destructure data (i.e., introduce bindings for parts of data), and bindings can be marked mutable, there doesn't seem to be a way to combine the two in the case of destructuring a reference, even though other combinations work:

struct X(i32);
let it = X(5);
let X(mut inside) = it;
inside = 1;

This may just be an edge case where other syntactic choices leave no good possibility. As you noticed, &mut x is already taken, and disambiguating with parentheses is not supported in patterns.

This isn't a big issue because there are several ways to do the same thing outside the pattern:

  1. Don't make the binding mutable in the pattern and then make a new, mutable binding (let mut x = x;)
  2. Don't destructure to begin with ‐ it's not terribly useful with references since you can just say let mut x = *reference;.

Trying to be too clever in argument lists is detrimental to readability anyway IMHO.

Upvotes: 3

Chronium
Chronium

Reputation: 1046

This seems to work on the Rust playground:

fn foo(mut a: &mut u64) {
    mutate(a);
}

Short answer is that you need to take in a mutable parameter that has the type of a mutable reference to a u64. I cannot provide a better answer, I'm still learning.

Here you can see a working example: Rust Playground

I am not 100% sure if I understand what you're asking, but it's worth a shot.

Upvotes: 1

Related Questions