Keeping track of a (child) struct who called a method in Rust - rust

I would like to create a add_ten method for MyStruct which keeps track of the child that called it (as a reference).
struct MyStruct<'a> {
value: i32,
child: Option<&'a mut MyStruct<'a>>,
}
impl MyStruct<'_> {
fn add_ten(&mut self) -> MyStruct {
MyStruct {
value: self.value + 10,
child: Some(self),
}
}
}
fn main() {
let mut a = MyStruct { value: 10, child: None }; // Create some struct
let b = a.add_ten(); // Process it and return the new struct with a ref of the child who called it
println!("{}", a.value); // Be able to read the value here
println!("{}", b.value); // and here
}
However I get this error:
error: lifetime may not live long enough
--> src/main.rs:10:9
|
9 | fn add_ten(&mut self) -> MyStruct {
| ---------
| |
| let's call the lifetime of this reference `'1`
| has type `&mut MyStruct<'2>`
10 | / MyStruct {
11 | | value: self.value + 10,
12 | | child: Some(self),
13 | | }
| |_________^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
|
= note: requirement occurs because of the type `MyStruct<'_>`, which makes the generic argument `'_` invariant
= note: the struct `MyStruct<'a>` is invariant over the parameter `'a`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
I understand that its a lifetime error, but I'm kind of stuck here :) I hope what I'm asking is clear enough, any help is appreciated!
EDIT
The reason I would like to use a reference, is to be able to come back to the childs and modify them. Something looking like this:
struct MyStruct<'a> {
value: i32,
child: Option<&'a mut MyStruct<'a>>,
}
impl MyStruct<'_> {
fn add_ten(&mut self) -> MyStruct {
MyStruct {
value: self.value + 10,
child: Some(self),
}
}
fn set_childs_to_zero(self) {
if self.child.is_none() { return; }
let mut child = self.child.unwrap();
loop {
child.value = 0;
if child.child.is_none() { break; }
child = child.child.unwrap();
}
}
}
fn main() {
let mut a = MyStruct { value: 10, child: None }; // Create some struct
let b = a.add_ten(); // Process it and return the new struct with a ref of the child who called it
println!("a: {}", a.value); // 10
println!("b: {}", b.value); // 20
b.set_childs_to_zero();
println!("a: {}", a.value); // 0
}

This might be a weird way of achieving what you are looking for. I doubt that it is the "right" way but hopefully someone can build off this and provide a better solution.
use std::rc::Rc;
struct MyStruct {
value: i32,
child: Option<Rc<MyStruct>>,
}
impl MyStruct {
fn add_ten(self) -> (Rc<MyStruct>, MyStruct) {
let s = Rc::new( self );
(
s.clone(),
MyStruct {
value: s.value + 10,
child: Some(s),
}
)
}
}
fn main() {
let a = MyStruct { value: 10, child: None }; // Create some struct
let (a, b) = a.add_ten(); // Process it and return the new struct with a ref of the child who called it
println!("{}", a.value); // Be able to read the value here
println!("{}", b.value); // and here
}
The use case you are describing is what Rc was built for - providing multiple ownership. You can read more about that in the documentation.

Related

Parent-child relation with Rc/RefCell not working

I just started with rust and am trying to implement a struct that has a parent and child.
The function set_child updates the child of the current X and sets the child's parent to be the current X, but I'm encountering many problems that I have a very rough understanding of and can't fix.
Any help is appreciated :)
main.rs
use std::{rc::Rc, cell::RefCell, borrow::BorrowMut};
struct X {
parent: Option<Rc<RefCell<X>>>,
child: Option<Rc<RefCell<X>>>,
value: i32,
}
impl X {
fn new() -> Self {
X {
parent: None,
child: None,
value: 10
}
}
fn set_child(&self, obj: Rc<RefCell<X>>) {
self.borrow_mut().child = Some(obj);
let &mut child = match self.child {
Some(x) => x.borrow_mut(),
None => todo!()
};
// no field `parent` on type `Rc<RefCell<X>>`
// and there is an error that says I cannot pass `self`
// it has to be a `Rc<RefCell<X>>`
child.parent = self;
}
}

How to resolve basic borrow issues?

I'm pretty new to rust and I'm stuck on whats probably a very simple question about borrowing. I've simplified my code to as below:
pub struct MyStruct {
pub val: i32
}
impl MyStruct {
pub fn new(val: i32) -> Self {
MyStruct {
val
}
}
}
pub struct MyStructVec {
pub vec: Vec::<MyStruct>
}
impl MyStructVec {
pub fn new() -> Self {
MyStructVec {
vec: Vec::new()
}
}
pub fn insert(&mut self, mut my_struct: MyStruct) {
self.vec.push(my_struct);
}
fn run(&mut self) {
for s in self.vec.iter_mut() {
s.val = s.val + 1;
self.edit(s);
}
}
fn edit(&self, my_struct: &mut MyStruct) {
my_struct.val = my_struct.val * 2;
}
}
fn main() {
let mut my_struct1 = MyStruct::new(69);
let mut my_struct2 = MyStruct::new(420);
let mut my_struct_vec = MyStructVec::new();
my_struct_vec.insert(my_struct1);
my_struct_vec.insert(my_struct2);
my_struct_vec.run();
}
When I run this i get the following error:
error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
--> src/main.rs:33:13
|
31 | for s in self.vec.iter_mut() {
| -------------------
| |
| mutable borrow occurs here
| mutable borrow later used here
32 | s.val = s.val + 1;
33 | self.edit(s);
| ^^^^ immutable borrow occurs here
But if I edit my code like this:
fn run(&mut self) {
for s in self.vec.iter_mut() {
s.val = s.val + 1;
//self.edit(s);
s.val = s.val * 2;
}
}
Then it runs perfectly fine. This examples a simplified case but in my actual code I might just want to separate out my code into a separate function for easier readability like with the edit function. So what is the proper way to do this in Rust? Thanks very much!
I think the error is that for some reason you are making your MyStructVec modify MyStruct when it could be simple a method on MyStruct. You are messing around with more references that you need, and you are not really taking the ones you need. It seems fair that edit should be encapsulated in the object that is gonna modify:
impl MyStruct {
...
fn edit(&mut self) {
self.val = self.val * 2;
}
}
...
impl MyStructVec {
...
fn run(&mut self) {
for s in self.vec.iter_mut() {
s.val = s.val + 1;
s.edit();
}
}
}
Playground

Parent <-> Child relation ownership problem

I'm just starting to learn Rust and I'm having some troubles understanding how ownership works in my case:
use std::ops::IndexMut;
// ================================================
struct Container {
root: Option<ContainerItem>,
items: Vec<ContainerItem>
}
impl Container {
pub fn create_item(&mut self) -> usize {
let item = create_test_item();
let idx = self.items.len();
self.items.push(item);
return idx;
}
pub fn get_item(&mut self, index: usize) -> &mut ContainerItem {
return self.items.index_mut(index);
}
pub fn new() -> Container {
let mut x = Container {
root: None,
items: Vec::new()
};
x.root = Some(create_test_item());
return x;
}
}
// ================================================
struct ContainerItem {
idx: usize,
children: Vec<usize>,
parent: usize,
has_parent: bool
}
impl ContainerItem {
pub fn add_child(&mut self, value: &mut ContainerItem) {
value.parent = self.idx;
value.has_parent = true;
self.children.push(value.idx);
}
}
// ================================================
fn create_test_item() -> ContainerItem {
ContainerItem {
idx: 1,
children: Vec::new(),
parent: 0,
has_parent: false
}
}
fn main() {
let mut container = Container::new();
let item_index = container.create_item();
let item = container.get_item(item_index);
if let Some(mut root) = container.root {
root.add_child(item);
}
}
I have a Container, with ContainerItems. Each ContainerItem can have children and also has a reference to its parent (both children and the parent are stored as their index in Container's items vec). This is all fine, adding items to the container works, but when I try to add a child to Container's root item (which is a ContainerItem), it throws errors:
error[E0503]: cannot use `container.root` because it was mutably borrowed
--> src/main.rs:68:12
|
66 | let item = container.get_item(item_index);
| --------- borrow of `container` occurs here
67 |
68 | if let Some(mut root) = container.root {
| ^^^^^^^^^^^^^^ use of borrowed `container`
69 | root.add_child(item);
| ---- borrow later used here
error[E0505]: cannot move out of `container.root.0` because it is borrowed
--> src/main.rs:68:17
|
66 | let item = container.get_item(item_index);
| --------- borrow of `container` occurs here
67 |
68 | if let Some(mut root) = container.root {
| ^^^^^^^^ move out of `container.root.0` occurs here
69 | root.add_child(item);
| ---- borrow later used here
If I change the call to add_child to use for e.g. create_test_item() as the argument, then it works fine.
I assume this might be because Container's items field has ownership over all ContainerItems? But I'm passing it by reference to add_child so I think this shouldn't matter, since I'm not changing the owner?
I think the trouble comes from the fact that in this Parent ←→ Child relation the items are sometimes referred to with references and sometimes with indices.
So, it is not always clear when the borrow should concern the container as a whole or just one item which is a part of it.
Moreover, the root item is not stored in the same place as the other items so no index can be used to refer to it.
I reorganised your code in order to always rely on indices (as far I understand your intention; maybe it is not always equivalent to what you wanted initially).
This way, as soon we have to adjust many indices, we just borrow the container as a whole.
Consequently, the add_child() method is moved from the item implementation to the container.
Note that the has_parent boolean was also a good opportunity to switch to Option.
Note also that, as long as we borrow an item with get_item() or get_item_mut(), we cannot create new items because the reallocation inside the Vec could invalidate the references; the borrow-checker will forbid that.
pub struct Container {
root: Option<usize>, // why not implicitly alway 0?
items: Vec<ContainerItem>,
}
impl Container {
pub fn create_item(&mut self) -> usize {
let idx = self.items.len();
let item = create_test_item(idx);
self.items.push(item);
idx
}
pub fn get_item(
&self,
index: usize,
) -> &ContainerItem {
&self.items[index]
}
pub fn get_item_mut(
&mut self,
index: usize,
) -> &mut ContainerItem {
&mut self.items[index]
}
pub fn new() -> Container {
let mut this = Container {
root: None,
items: Vec::new(),
};
this.root = Some(this.create_item());
this
}
pub fn add_child(
&mut self,
parent_idx: usize,
child_idx: usize,
) {
// forget child in previous parent if any
if let Some(prev_parent_idx) = self.items[child_idx].parent {
let prev_children = &mut self.items[prev_parent_idx].children;
let idx = prev_children.iter().position(|i| *i == child_idx);
prev_children.remove(idx.unwrap());
}
// give the child its new parent
let child = &mut self.items[child_idx];
child.parent = Some(parent_idx);
// append this new child to the parent
let parent = &mut self.items[parent_idx];
parent.children.push(child_idx);
}
}
#[derive(Debug)]
pub struct ContainerItem {
idx: usize,
children: Vec<usize>,
parent: Option<usize>,
}
fn create_test_item(idx: usize) -> ContainerItem {
ContainerItem {
idx,
children: Vec::new(),
parent: None,
}
}
fn main() {
let mut container = Container::new();
let item_idx = container.create_item();
println!("item: {:?}", container.get_item(item_idx));
if let Some(root_idx) = container.root {
println!("root: {:?}", container.get_item(root_idx));
println!("~~~~~~~~");
container.add_child(root_idx, item_idx);
println!("item: {:?}", container.get_item(item_idx));
println!("root: {:?}", container.get_item(root_idx));
}
}
let item = container.get_item(item_index);
if let Some(mut root) = container.root {
root.add_child(item);
}
container.get_item has already borrowed a value from &self. Therefore root.add_child will be restricted as long as that borrow exists.
Since the goal is simply to add an element to vec, there is no need to even have the attribute root: Option<ContainerItem>. By default when a new container is created, items can be an empty vector and when there is an item to be added it can be pushed to the vector.
Here is a simple way to implement the parent-child relationship
struct Parent<'a> {
children: &'a mut Vec<Child>,
}
impl Parent<'_> {
pub fn add(&mut self, c: Child) -> () {
let root = &mut self.children;
root.push(c)
}
pub fn get_item(
&self,
index: usize,
) -> &Child {
&self.children[index]
}
}
struct Child {
i: i32,
}
fn main() {
let c1 = Child { i: 1 };
let mut data = vec![c1];
let c12 = Child { i: 1 };
data.push(c12);
let mut p = Parent { children: &mut data };
let c12 = Child { i: 2 };
p.add(c12);
let item = p.get_item(2);
println!("{}", item.i) //2
Obviously other traits can be added to the parent

Using a struct to store a reference to a non-Copy value

I need an object that contains a reference to a process child and enables me to execute functions on it.
pub struct Shell {
child: std::process::Child,
}
impl Shell {
pub fn init() -> Shell {
let mut cmd = std::process::Command::new("Command");
let process = cmd.spawn();
let new = Shell {
child: process.unwrap(),
};
new
}
pub fn f1(mut self) {
//do something with self
}
pub fn f2(mut self) {
{
let stdin = self.child.stdin.as_mut().unwrap();
}
let output = self.child.wait_with_output();
}
}
fn main() {
let mut shell = Shell::init();
shell.f1();
shell.f2();
}
error[E0382]: use of moved value: `shell`
--> src/main.rs:28:5
|
27 | shell.f1();
| ----- value moved here
28 | shell.f2();
| ^^^^^ value used here after move
|
= note: move occurs because `shell` has type `Shell`, which does not implement the `Copy` trait
>Try it
The problem is that when I initialize my object, I can call functions on the object only once, because the value is moved on the first call due to standard Rust behaviour.
A simple #[derive(Copy, Clone)] does not work here, because std::process::Child does not seem to implement the Copy trait. Is there a way to circumvent that or wrap it into something copy-able?
Test Implementations
When using a mutable reference as the function argument, the initial problem appears to be solved, however, it is then not possible to access the self.child more than once.
pub struct Shell {
child: std::process::Child,
}
impl Shell {
pub fn init() -> Shell {
let mut cmd = std::process::Command::new("Command");
let process = cmd.spawn();
let new = Shell {
child: process.unwrap(),
};
new
}
pub fn f1(&mut self) {
//do something with self
}
pub fn f2(&mut self) {
{
let stdin = self.child.stdin.as_mut().unwrap();
}
let output = self.child.wait_with_output();
}
}
fn main() {
let mut shell = Shell::init();
shell.f1();
shell.f2();
}
error[E0507]: cannot move out of borrowed content
--> src/main.rs:21:22
|
21 | let output = self.child.wait_with_output();
| ^^^^ cannot move out of borrowed content
>Try it
Is there a way to solve that?
The problem is that self.child has to be consumed by wait_with_output(). This is why self must not be passed to f2 by reference, but by value:
pub struct Shell {
child: std::process::Child,
}
impl Shell {
pub fn init() -> Shell {
let mut cmd = std::process::Command::new("Command");
let process = cmd.spawn();
let new = Shell {
child: process.unwrap(),
};
new
}
pub fn f1(&mut self) {
//do something with self
}
pub fn f2(mut self) {
{
let stdin = self.child.stdin.as_mut().unwrap();
}
let output = self.child.wait_with_output();
}
}
fn main() {
let mut shell = Shell::init();
shell.f1();
shell.f2();
}
>Try it
However this implies that f2 must be the last function that accesses self.child.

How to change the variable from inside Fn closure in Rust?

I have the following code (playground):
struct A {
pub vec: Vec<u64>,
}
impl A {
fn perform_for_all<F: Fn(&mut u64)>(&mut self, f: F) {
for mut i in &mut self.vec {
f(i);
}
}
}
fn main() {
let mut a = A {
vec: vec![1, 3, 44, 2, 4, 5, 6],
};
let mut done = false;
a.perform_for_all(|v| {
println!("value: {:?}", v);
done = true;
});
if !done {
a.perform_for_all(|v| {
println!("value {:?}", v);
});
}
}
The following errors occur:
error[E0594]: cannot assign to `done`, as it is a captured variable in a `Fn` closure
--> src/main.rs:21:9
|
21 | done = true;
| ^^^^^^^^^^^ cannot assign
|
help: consider changing this to accept closures that implement `FnMut`
--> src/main.rs:19:23
|
19 | a.perform_for_all(|v| {
| _______________________^
20 | | println!("value: {:?}", v);
21 | | done = true;
22 | | });
| |_____^
I have a list of loaded objects and a list of objects in a database. I need a function that takes a closure and executes it on the loaded objects and if we don't have the objects in the list, execute it on a list of objects from the database.
That function looks like:
pub fn perform_for_match_with_mark<F>(&mut self, mark: MatchMark, f: F)
where
F: Fn(&mut GameMatch),
{
self.perform_for_all_matches(
|m| {
// runtime list
if let Game::Match(ref mut gm) = *m {
if gm.match_stamp().mark == mark {
f(gm);
}
}
},
None,
);
// if we have called `f` above - don't execute lines below.
let tx = self.match_tx.clone();
GamesDatabase::perform_for_match_with_mark(mark, |ms| {
// database
self.perform_for_all_matches(
|m| {
if let Game::Match(ref gm) = *m {
if gm.match_stamp().id == ms.id {
f(&mut GameMatch::new_with_match_stamp(
tx.clone(),
ms.clone(),
gm.needs_server_set,
gm.server_id,
))
}
}
},
None,
);
});
}
We have to operate on objects from the database only if we were unable to find them in runtime list. That is why I decided to make a variable which says "we already found these objects in the list, leave the database alone".
Change your perform_for_all function to use FnMut instead of Fn:
fn perform_for_all<F>(&mut self, mut f: F)
where
F: FnMut(&mut u64),
{
for mut i in &mut self.vec {
f(&mut i);
}
}
As Peter said, there is some compiler magic going on.
The signature for Fn::call is:
extern "rust-call" fn call(&self, args: Args) -> Self::Output
This takes an immutable reference to self, which is why you can't modify any of the captured variables.
The signature for FnMut::call_mut lets you mutate variables because it takes &mut self:
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output
By changing your closure from Fn to FnMut, you allow it to modify its captured variables, given that the references you pass to it are mutable.
Just to expand a little on SplittyDev's answer.
When you use a closure, the compiler does some magic to let the closure access variables in its environment. Effectively it will create a new struct, whose members are the variables that you tried to access.
It's not exactly this (which won't actually compile), but it's a reasonable approximation conceptually:
struct Closure_1 {
done: bool
}
impl FnMut<&mut u64> for Closure_1 {
fn call_mut(&mut self, v: &mut u64) {
println!("value: {:?}", v);
self.done = true;
}
}
And when you call it, those variables will be borrowed or copied (or moved if you use move keyword).
let mut c1 = Closure_1 { done : done };
a.perform_for_all(|v| c1.call(&v));
done = c1.done;
When the closure modifies its environment, it cannot be a Fn because it must also mutate the variables on itself:
impl Fn<&mut u64> for Closure_1 {
fn call(&self, v: &mut u64) {
println!("value: {:?}", v);
self.done = true; // Can't do this because self is not a mutable ref
}
}
See The Rust Programming Language section on closures and their environment for more information.

Resources