Take ownership/move Vec through reference

I have a struct with a Vec field and i want following feature:

  • Have read-only access to the vec field
  • Be able to take ownership of the vec.

This is what I've got so far:

#![allow(dead_code)]
#![allow(unused_variables)]

pub mod foo_mod {
    pub struct Foo {
        //other data ...
        vec: Vec<i32>,
    }

    impl Foo {
        pub fn new(vec: Vec<i32>) -> Self {
            // other data may be passed to ctor
            Foo { vec }
        }

        pub fn vec(&self) -> &Vec<i32> {
            &self.vec
        }
    }
}

pub mod bar_mod {
    pub struct Bar {
        // other data ...
        vec: Vec<i32>,
    }

    impl Bar {
        pub fn new(vec: Vec<i32>) -> Bar {
            // other data may be passed to ctor
            Bar { vec }
        }
        pub fn vec(&self) -> &Vec<i32> {
            &self.vec
        }
    }
}

fn main() {
    use crate::bar_mod::Bar;
    use crate::foo_mod::Foo;
    let vec = vec![1, 2, 3];
    let foo = Foo::new(vec);
    // Read only access
    for value in foo.vec().iter() {
        println!("foo: {}", value)
    }
    // Want to take ownership here -- the problem is here:
    let bar = Bar::new(
        foo.vec().to_vec(), // Copy occurs here, can I just move/take ownership ?
    );
    // This one is fine
    for value in bar.vec().iter() {
        println!("bar: {}", value)
    }
    // This one is ok but should not if foo was moved before
    for value in foo.vec().iter() {
        println!("foo: {}", value)
    }
}


(Playground)

Can I just move foo.vec to bar.vec ?

Thanks!

You can't move out of an & reference, because it does not allow you to mutate what it refers to. You can make it work using an &mut reference, but you would need to use mem:: replace to ensure the original is not left uninitialised.

However, what it appears you want to do is create a Bar with the same vec field as a Foo. If you are okay with the Foo being unusable afterwards, then you can just move the vec:

let bar = Bar {
   vec: foo.vec,
};

(Playground)

You can add a method which consumes self and provides an owned Vec: playground.

Thanks for your answer!

You can't move out of an & reference

Is it always true in Rust ?

However, what it appears you want to do is create a Bar with the same vec field as a Foo . If you are okay with the Foo being unusable afterwards, then you can just move the vec

I agree it can be a solution but in my real case, Foo fields are private and in a sibling module preventing any access to vec. I would like to keep this encapsulation. I will update OP.

EDIT : OP edited.

Yes. An & reference is always immutable. You can define a function that destroys Foo and returns the vector by value:

impl Foo {
    pub fn take_vec(self) -> Vec<i32> {
        self.vec
    }
}

Thanks for your answer.

This seems equivalent to what is into_iter: into_iter method

Seems to be the best solution thanks.

Thanks for your answer.

Just one follow up question.
If my struct is defined as:

struct Foo {
    vec: Vec<i32>,
    any: SomeHeapAllocatedStruct
}

does take_vec will drop any ?

Consuming the struct means that anything you don't return will be dropped. You can make these accessible through other means if necessary. One example would be storing a ref-counted pointer instead of owning the child type (shared ownership).

Yes, take_vec will drop any because it has ownership of self, so the destructer is executed when self goes out of scope at the end of take_vec.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.