Design pattern for borrowing out a field of struct


#1

I want to write a struct that borrows its field such as,

struct SomeStruct {
     v: i32,
}
struct Example {
     a: SomeStruct,
     b: SomeStruct,
}

impl Example {
    fn swap(mut self) { // using mut sef to borrow fields
        let tmp = self.a;
        self.a = self.b;
        self.b = tmp;
    }
}

fn main() {
    let x = Example {
        a: SomeStruct { v: 0 },
        b: SomeStruct { v: 1 },
    };
    x.swap();
    x.swap(); // compiler error: use of moved value
}

I understand an error for last line, and changing swap to return self and changing x mutable and reassign solves the error.

But my actual code has a struct with Example like field.
Do I need “bollow and return” again?
I feel something wrong about my thought.


#2

Taking self by value, like self or mut self moves ownership and stops you being able to access it any more. If you want to mutate without losing control, a mutable reference like &mut self is required, and then you’ll need to be careful about how the swap is performed. The easiest and best way is via std::mem::swap (that and replace are extremely useful functions).


#3

Swap was an example, but it is the first time for me to hear about mem::swap and mem::replace!
Maybe I can solve my problem.

Thank you!


#4

Since the function is swap(mut self) doesn’t that mean after the first call to swap() that the object is destroyed? It’s basically passing “x” into swap swap() and swap doesn’t return it, therefor swap must destroy it?


#5

I do not understand what you are saying…
What I indicated at last in my first post is,

struct SomeStruct {
    v: i32,
}
struct Example {
    a: SomeStruct,
    b: SomeStruct,
}

impl Example {
    fn swap(mut self) -> Example { // using mut sef to borrow fields
        let tmp = self.a;
        self.a = self.b;
        self.b = tmp;
        self
    }
}

fn main() {
    let mut x = Example {
        a: SomeStruct { v: 0 },
        b: SomeStruct { v: 1 },
    };
    x = x.swap();
    x = x.swap(); // no error
}

#6

I think this is what you want:

use std::mem;

struct SomeStruct {
     v: i32,
}
struct Example {
     a: SomeStruct,
     b: SomeStruct,
}

impl Example {
    fn swap(&mut self) {
        mem::swap(&mut self.a, &mut self.b)
    }
}

fn main() {
    let mut x = Example {
        a: SomeStruct { v: 0 },
        b: SomeStruct { v: 1 },
    };
    x.swap();
    x.swap();
}

#7

Yes by passing in:

fn swap(mut self) -> Example {

instead of:

fn swap(&mut self) -> Example {

You are passing in the object, instead of a reference to the object. Which means you passed ownership of the object into the swap() method. Since the function is not returning the object, the object is “lost” when the function returns. When you pass in the mutable reference the function is just borrowing the object, and so it still exists once the function returns.