Reputation: 5407
I have the following code
pub struct PropertyDeclarationBlock {
pub declarations: Arc<Vec<(PropertyDeclaration, PropertyDeclarationImportance)>>
}
impl PropertyDeclarationBlock {
pub fn select_declarations(&self) -> Arc<Vec<PropertyDeclaration>> {
Arc::new(self.declarations.clone().map_in_place(|p| {
let (declaration, _) = p;
declaration
}))
}
}
I want to be able to call .select_declarations() on a PropertyDeclarationBlock and have it return a clone of the declarations but instead of it being a Arc Vec (PropertyDeclaration, PropertyDeclarationImportance) be only a Arc Vec PropertyDeclaration, in other words returning a a vector of PropertyDeclaration instead of the previous tuple.
The previous won't compile as I am getting the following error:
error: cannot move out of dereference of `&`-pointer
Arc::new(self.declarations.clone().map_in_place(|p| {
^~~~~~~~~~~~~~~~~~~~~~~~~
From what I understand, since the function take self as a parameter it will take ownership of it. Since I'd rather have the function burrow self I use the &.
EDIT
Here is the error message after implementing the new function:
error: cannot move out of dereference of `&`-pointer
Arc::new(self.declarations.iter().map(|&(declaration, _)| declaration).collect())
^~~~~~~~~~~~~~~~~
note: attempting to move value to here (to prevent the move, use `ref declaration` or `ref mut declaration` to capture value by reference)
Arc::new(self.declarations.iter().map(|&(declaration, _)| declaration).collect())
^~~~~~~~~~~
I tried applying the ref keyword before declaration as suggested by the error message but it didn't help.
Upvotes: 0
Views: 2320
Reputation: 65712
self.declarations.clone()
clones the Arc
, while I believe you intended to clone the Vec
. To resolve the call to map_in_place
, the compiler automatically dereferences the Arc
to be able to call the method, which is defined on Vec
. The compiler knows how to dereference the Arc
because Arc
implements Deref
. deref
returns a borrowed pointer, and this is where the error comes from. To clone the Vec
, we must explicitly dereference the Arc
: (*self.declarations).clone()
.
However, map_in_place
is not suitable in this case, as (PropertyDeclaration, PropertyDeclarationImportance)
doesn't have the same size as PropertyDeclaration
(unless PropertyDeclarationImportance
has a size of zero, which is probably not the case), which is required per the docs. It fails with a message similar to this:
task '<main>' failed at 'assertion failed: mem::size_of::<T>() == mem::size_of::<U>()', /build/rust-git/src/rust/src/libcollections/vec.rs:1805
Here's a proper implementation:
impl PropertyDeclarationBlock {
pub fn select_declarations(&self) -> Arc<Vec<PropertyDeclaration>> {
Arc::new(self.declarations.iter().map(|&(declaration, _)| declaration).collect())
}
}
Here, we use iter
on the Vec
to create an iterator over the vector's items. This returns an Items
, which implements Iterator
on immutable references.
Then, we use map
to lazily map (PropertyDeclaration, PropertyDeclarationImportance)
to PropertyDeclaration
. Note how we destructure the tuple and the reference in the closure's parameter list (this works in fn
s too) instead of using a let
statement.
Finally, we use collect
to create a new collection container for this sequence. collect
's result is generic; it can be any type that implements FromIterator
. Vec
implements FromIterator
, and the compiler infers Vec
from the method's signature.
Upvotes: 1