I have a struct that has a vector of another struct type.
struct Element {
val: String,
}
struct Collection {
elements: Vec<Element>,
}
impl Collection {
fn process(&mut self) {
for entry in &self.elements.iter_mut() {
entry.val = "New value".to_string();
println!("{}", entry.val);
}
}
}
fn main() {
let e1 = Element {
val: "My first entry".to_string(),
};
let e2 = Element {
val: "My second entry".to_string(),
};
let mut c = Collection { elements: vec![] };
c.elements.push(e1);
c.elements.push(e2);
c.process();
}
When I try to iterate over it, I get the following error:
error[E0277]: the trait bound `&std::slice::IterMut<'_, Element>: std::iter::Iterator` is not satisfied
--> src/main.rs:11:22
|
11 | for entry in &self.elements.iter_mut() {
| -^^^^^^^^^^^^^^^^^^^^^^^^
| |
| `&std::slice::IterMut<'_, Element>` is not an iterator; maybe try calling `.iter()` or a similar method
| help: consider removing 1 leading `&`-references
|
= help: the trait `std::iter::Iterator` is not implemented for `&std::slice::IterMut<'_, Element>`
= note: required by `std::iter::IntoIterator::into_iter`
I think this is because &self.elements is really a reference. Using self.elements would work, but I was hoping to modify the actual objects rather than a copy.
What would be a proper way of doing this?
Switch to this:
for entry in self.elements.iter_mut() { /* ... */ }
Or more idiomatically:
for entry in &mut self.elements { /* ... */ }
IterMut contains a reference to the items in the vector (and thus will change the vector items directly), but it is itself an object on the stack that will be changed as the iteration progresses.
the trait bound `&std::slice::IterMut<'_, Element>: std::iter::Iterator` is not satisfied
This is saying that you've got an IterMut by reference. That is, the precedence is different from what you think it is:
&self.elements.iter_mut()
&(self.elements.iter_mut()) // Is this
(&self.elements).iter_mut() // Not this
However, we'd have to do something like this:
(&mut self.elements).iter_mut()
because iter_mut needs a mutable reference as the receiver. Rust understands that and lets us just do the straightforward version and appropriately pass the mutability around:
self.elements.iter_mut()
Related
im trying to return a &str slice from a String which is behind a an Rc<RefCell<>>
use std::rc::Rc;
use std::cell::{
RefCell,
Ref
};
struct Data {
data: Rc<RefCell<String>>
}
impl Data {
fn set(
&mut self,
data: String
) {
*self.data.borrow_mut() = data;
}
// TODO: fix here
fn get(&self) -> &str {
self.data.borrow().as_str()
}
}
fn main() {
let mut data = Data {
data: Rc::new(RefCell::new(String::new()))
};
data.set(String::from("how can i solve this?"));
let d = data.get();
println!("{}", d);
}
here's the compilation error
error[E0515]: cannot return reference to temporary value
--> questions/refcell-data-inspection/src/main.rs:21:9
|
21 | self.data.borrow().as_str()
| ------------------^^^^^^^^^
| |
| returns a reference to data owned by the current function
| temporary value created here
well, i understand its a temporary value crated because borrow returns a guard, which will go out of scope.
how can i fix this in order to return a &str slice from that String?
Well, as you said yourself "borrow guard" will be out of scope at the one of a function, so you cannot do that. Think of it that way. If you managed to return a reference into String, how would RefCell know that this reference exists and that it cannot give for example a mutable reference.
Only thing that you can do is to return that guard. This would mean, that you must change function's signature, but it will be as usable as a &str would be. So try this:
fn get(&self) -> Ref<'_, String> {
self.data.borrow()
}
EDIT. You might want to also look at that question: How to borrow the T from a RefCell<T> as a reference?
So I have some code like this:
use std::borrow::Borrow;
use std::cell::RefCell;
use std::collections::HashMap;
use std::ops::Index;
use std::rc::Rc;
struct Data {
// ...
}
struct TableTreeNode {
father: Option<Rc<RefCell<TableTreeNode>>>,
table: HashMap<String, Data>,
}
impl Index<&str> for TableTreeNode {
type Output = Data;
fn index(&self, index: &str) -> &Self::Output {
if self.table.contains_key(index) {
self.table.index(index)
} else {
//recursively goes up
let father: &RefCell<TableTreeNode> = self.father.as_ref().expect("not found");
father.borrow().index(index)
}
}
}
It fails on compile:
error[E0515]: cannot return reference to temporary value
--> xxx.rs:25:13
|
25 | father.borrow().index(index)
| ---------------^^^^^^^^^^^^^
| |
| returns a reference to data owned by the current function
| temporary value created here
I have no clue to solve this. How would a borrow from a RefCell could be a temporary variable? If I'm doing this wrong, what's the right way to implement these?
Because RefCell::borrow() returns a Ref guard. This guard implements Deref, and when it is dropped it marks the RefCell as no longer borrowed.
Generally, you cannot hide a RefCell across API boundaries if you use it. You have to return a Ref<Something> or RefMut<Something> instead os &[mut] Something. And because the signature of Index is constant and expecting a reference, that means you cannot implement Index.
I would like to know examples where keeping a T type within Box would be unsafe, while within Pin it would be safe.
Initially, I thought that std::marker::PhantomPinned prevents an instance from being moved around (by forbidding it), but seemingly it does not. Since:
use std::pin::Pin;
use std::marker::PhantomPinned;
#[derive(Debug)]
struct MyStruct {
field: u32,
_pin: PhantomPinned
}
impl MyStruct {
fn new(field: u32) -> Self {
Self {
field,
_pin: PhantomPinned,
}
}
}
fn func(x: MyStruct) {
println!("{:?}", x);
func2(x);
}
fn func2(x: MyStruct) {
println!("{:?}", x);
}
fn main() {
let x = MyStruct::new(5);
func(x);
}
this code is compilable, despite the fact that it moves MyStruct from main to func and etc.
as for Box and Pin they both keep their contents on the heap, so it does not seem to be subjected to motions.
Thus, I would appreciate if someone elaborated this topic on these questions. Since it is not covered in other questions and docs, what is inherently wrong with just getting by with Box.
I think you misunderstand.
PhantomPinned does not make data immovable. It just says that once the data is pinned, it will never be able to be unpinned again.
Therefore, to make data with PhantomPinned unmovable, you have to Pin it first.
For example, if you create a pinned version of your MyStruct variable, you cannot unpin it:
fn main() {
let pinned_x = Box::pin(MyStruct::new(5));
let unpinned_x = Pin::into_inner(pinned_x);
}
error[E0277]: `PhantomPinned` cannot be unpinned
--> src/main.rs:20:38
|
20 | let unpinned_x = Pin::into_inner(pinned_x);
| --------------- ^^^^^^^^ within `MyStruct`, the trait `Unpin` is not implemented for `PhantomPinned`
| |
| required by a bound introduced by this call
|
= note: consider using `Box::pin`
note: required because it appears within the type `MyStruct`
--> src/main.rs:4:8
|
4 | struct MyStruct {
| ^^^^^^^^
note: required by a bound in `Pin::<P>::into_inner`
--> /home/martin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/pin.rs:482:23
|
482 | impl<P: Deref<Target: Unpin>> Pin<P> {
| ^^^^^ required by this bound in `Pin::<P>::into_inner`
While with a normal struct, you can unpin it without a problem:
struct MyUnpinnableStruct;
fn main() {
let pinned_x = Box::pin(MyUnpinnableStruct);
let unpinned_x = Pin::into_inner(pinned_x);
}
Difference between Pin and Box
They are both completely different concepts. Pin makes sure that the data it points to cannot be moved. Box puts something on the heap.
As you can see from the previous examples, both are often used in conjunction, as the easiest way to prevent something from moving is to put it on the heap.
PhantomPin causes classes to be !Unpin, meaning once they are pinned, they can no longer be unpinned.
You can try to use Pin on values on the stack, but you will run into problems quickly. While it works for unpin-able structs:
struct MyUnpinnableStruct(u32);
fn main() {
let y = MyUnpinnableStruct(7);
{
let pinned_y = Pin::new(&y);
}
// This moves y into the `drop` function
drop(y);
}
It fails for structs that contain PhantomPinned:
fn main() {
let x = MyStruct::new(5);
{
// This fails; pinning a reference to a stack object
// will fail, because once we drop that reference the
// object will be movable again. So we cannot `Pin` stack objects
let pinned_x = Pin::new(&x);
}
// This moves x into the `drop` function
drop(x);
}
error[E0277]: `PhantomPinned` cannot be unpinned
--> src/main.rs:24:33
|
24 | let pinned_x = Pin::new(&x);
| -------- ^^ within `MyStruct`, the trait `Unpin` is not implemented for `PhantomPinned`
| |
| required by a bound introduced by this call
|
= note: consider using `Box::pin`
note: required because it appears within the type `MyStruct`
--> src/main.rs:4:8
|
4 | struct MyStruct {
| ^^^^^^^^
note: required by a bound in `Pin::<P>::new`
--> /home/martin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/pin.rs:482:23
|
482 | impl<P: Deref<Target: Unpin>> Pin<P> {
| ^^^^^ required by this bound in `Pin::<P>::new`
Box without Pin
While the content of Box is on the heap and therefore has a constant address, you can still move it back from the heap to the stack, which wouldn't be possible with a Pin object:
// Note that MyData does not implement Clone or Copy
struct MyData(u32);
impl MyData {
fn print_addr(&self) {
println!("Address: {:p}", self);
}
}
fn main() {
// On the heap
let x_heap = Box::new(MyData(42));
x_heap.print_addr();
// Moved back on the stack
let x_stack = *x_heap;
x_stack.print_addr();
}
Address: 0x557452040ad0
Address: 0x7ffde8f7f0d4
Enforcing Pin
To make sure that an object is pinned in a member function, you can use the following syntax:
fn print_addr(self: Pin<&Self>)
Together with PhantomPinned, you now can be 100% sure that print_addr will always print the same address for the same object:
use std::{marker::PhantomPinned, pin::Pin};
struct MyData(u32, PhantomPinned);
impl MyData {
fn print_addr(self: Pin<&Self>) {
println!("Address: {:p}", self);
}
}
fn main() {
// On the heap
let x_pinned = Box::pin(MyData(42, PhantomPinned));
x_pinned.as_ref().print_addr();
// Moved back on the stack
let x_unpinned = Pin::into_inner(x_pinned); // FAILS!
let x_stack = *x_unpinned;
let x_pinned_again = Box::pin(x_stack);
x_pinned_again.as_ref().print_addr();
}
In this example, there is absolutely no way to ever unpin x_pinned again, and print_addr can only be called on the pinned object.
Why is this useful? For example because you can now work with raw pointers, as is required in the Future trait.
But in general, Pin is only really useful if paired with unsafe code. Without unsafe code, the borrow checker is sufficient to keep track of your objects.
I want to collect changes to a struct and apply them all at once.
The basic outline looks like this:
enum SomeEnum {
Foo,
Bar,
}
struct SomeStruct {
attrib: SomeEnum,
next_attrib: Option<SomeEnum>,
}
impl SomeStruct {
pub fn apply_changes(&mut self) {
if let Some(se) = self.next_attrib {
self.attrib = se;
}
self.next_attrib = None;
}
}
which yields the following compiler error:
error[E0507]: cannot move out of borrowed content
--> src/lib.rs:13:27
|
13 | if let Some(se) = self.next_attrib {
| -- ^^^^ cannot move out of borrowed content
| |
| hint: to prevent move, use `ref se` or `ref mut se`
I found Get an enum field from a struct: cannot move out of borrowed content and added #[derive(Clone, Copy)] to my enum's definition.
This may work but I feel uncomfortable about (implicitly) using copying since this could generally happen to larger datatypes as well.
The actual owner is never moved out of the struct.
Is there another way to accomplish this, without exposing the Copy/Clone traits to all users of the enum?
Essentially, you can't assign the value to self.attrib if it's still owned by self.next_atrrib. That means you need to remove the value from self.next_attrib and then give ownership to self.attrib.
One way to do this would be to manually replace the value. For instance, you could use std::mem::replace to replace the value with None and take ownership of the current value as next_attrib. Then you can take the value and, if it is Some(_), you can place its content in self.attrib.:
impl SomeStruct {
pub fn apply_changes(&mut self) {
let next_attrib = std::mem::replace(&mut self.next_attrib, None);
if let Some(se) = next_attrib {
self.attrib = se;
}
}
}
Since this is a relatively common pattern, however, there is a utility function on Option to handle situations where you'd like to take ownership of the contents of an Option and set the Option to None. The Option::take method is what you want.
impl SomeStruct {
pub fn apply_changes(&mut self) {
if let Some(se) = self.next_attrib.take() {
self.attrib = se;
}
}
}
See also:
How can I swap in a new value for a field in a mutable reference to a structure?
I thought I got the idea of move semantics until this code.
fn main() {
let v = Data {
body: vec![10, 40, 30],
};
p(&v);
}
fn p(d: &Data) {
for i in d.body {
// &d.body, Why d.body move?
println!("{}", i);
}
}
struct Data {
body: Vec<i32>,
}
error[E0507]: cannot move out of borrowed content
--> src/main.rs:9:14
|
9 | for i in d.body {
| ^^^^^^ cannot move out of borrowed content
error[E0507]: cannot move out of `d.body` which is behind a `&` reference
--> src/main.rs:9:14
|
8 | fn p(d: &Data) {
| ----- help: consider changing this to be a mutable reference: `&mut Data`
9 | for i in d.body {
| ^^^^^^
| |
| cannot move out of `d.body` which is behind a `&` reference
| `d` is a `&` reference, so the data it refers to cannot be moved
I passed a reference, and I accessed a field via auto-deref feature, so why is it a move?
What you are doing is field accessing on pointer.
Check Field Access Expression :
if the type of the expression to the left of the dot is a pointer, it
is automatically dereferenced as many times as necessary to make the
field access possible
Sample for how Rust evaluates Field Access Expression on Borrowed Content :
let d = Data { /*input*/}
let body = (&d).body // -> (*&d).body -> d.body
let ref_body = &(&d).body // -> &(*&).body -> &d.body -> &(d.body)
Note : d is still borrowed content, auto deref is just needed to access the fields.
Why move ?
Consider this code:
struct Data {
body: Vec<i32>,
id: i32,
}
fn p(mut d: &Data) {
let id = d.id;
}
This code will work as expected and there will be no moves in here so you will able to reuse d.id. In this situation:
Rust will try to copy the value of d.id. Since d.id is i32 and implements the Copy trait, it will copy the value to id.
Consider this code:
fn p(mut d: &Data) {
let id = d.id; // works
let body = d.body; // fails
}
This code will not work because:
Rust will try to copy d.body but Vec<i32> has no implementation of the Copy trait.
Rust will try to move body from d, and you will get the "cannot move out of borrowed content" error.
How does this effect the loop?
From the reference
A for expression is a syntactic construct for looping over elements provided by an implementation of std::iter::IntoIterator
A for loop is equivalent to the following block expression.
'label: for PATTERN in iter_expr {
/* loop body */
}
is equivalent to
{
let result = match IntoIterator::into_iter(iter_expr) {
mut iter => 'label: loop {
let mut next;
match Iterator::next(&mut iter) {
Option::Some(val) => next = val,
Option::None => break,
};
let PAT = next;
let () = { /* loop body */ };
},
};
result
}
This means your vector must have an implementation of IntoIterator because IntoIterator::into_iter(self) expects self as an argument. Luckily, both impl IntoIterator for Vec<T>, another is impl<'a, T> IntoIterator for &'a Vec<T> exist.
Why does this happen?
Simply:
When you use &d.body, your loop uses the &Vec implementation of IntoIterator.
This implementation returns an iterator which points at your vector's slice. This means you will get the reference of elements from your vector.
When you use d.body, your loop uses the Vec implementation of IntoIterator.
This implementation returns an iterator which is a consuming iterator. This means your loop will have the ownership of actual elements, not their references. For the consuming part this implementation needs the actual vector not the reference, so the move occurs.
You are accessing the field body in d. body itself is a Vec<i32> which is not a reference. If you would use d directly, no & would be necessary, but since you are accessing a field in d, you must specify that you want to have the reference to the field.
Basically d owns body. If you borrow d you cannot steal body, it belongs to d but you can borrow it.
This loop will be desugared into something similar to the following:
let mut iter = IntoIterator::into_iter(v);
loop {
match iter.next() {
Some(x) => {
// loop body
},
None => break,
}
}
As you can see, it's using into_iter, which moves the vector d.body.