Is ref really a legacy pattern?


#1

The book has this section:

The ref keyword is like the opposite of & in patterns; this says “please bind ref to be a &String , don’t try to move it out. In other words, the & in &Some is matching against a reference, but ref creates a reference. ref mut is like ref , but for mutable references.

Anyway, today’s Rust doesn’t work like this. If you try to match on something borrowed, then all of the bindings you create will attempt to borrow as well. This means that the original code works as you’d expect.

Because Rust is backwards compatible, we couldn’t remove ref and ref mut , and they’re sometimes useful in obscure situations, where you want to partially borrow part of a struct as mutable and another part as immutable. But you may see them in older Rust code, so knowing what they do is still useful.

However, I just struggled for quite a while trying to figure out why updating an array in a destructure wasn’t affecting the original array… after all, I received the struct as a reference - why wouldn’t it work?

Sample gotcha code:

struct Foo {
    a:[f32;4],
    b:[f32;4]
}

impl Foo {
    pub fn new() -> Foo {
        Foo{
            a: [0.0;4],
            b: [0.0;4],   
        }
    }
}

fn do_stuff(foo:&mut Foo) {
    //this works
    let Foo {ref mut a, mut b} = foo;
    
    //this fails:
    //let Foo {mut a, mut b} = foo;
    
    a[0] = 1.0;
    foo.b[0] = 1.0;
    
    assert!(foo.a[0] == 1.0);
    assert!(foo.b[0] == 1.0);
}

fn main() {
    let mut foo = Foo::new();
    do_stuff(&mut foo);
}


#2

Oh nevermind… I see that there are other ways of doing it which don’t cause that problem…

Specifically, here this works:

let Foo {a, b} = foo;

And in my actual example where I was getting stuck, destructuring like this works:

let Foo {a,b} = &mut self.data;

(though leaving the &mut off there does not…)

I’m still not entirely sure of where “&mut” goes in various circumstances like this… back to the book! :wink:


#3

I believe, that if you specify mut a, mut b then the compiler will think that you’re trying to specify the modifiers (ref and mut) and therefore not infer them, and in the second bit of code where you mention the necessity of &mut, if I read it correctly, the docs you quoted meant that specifying you’re destructuring a reference to a variable makes all the variables you’re destructuring references as well. It’s abit murky in this case because [f32; 4] is Clone and therefore will be cloned when necessary.