You can run the code below here.
use std::rc::Rc;
use std::cell::RefCell;
#[derive(Debug)]
pub struct Turtle{
name: String,
children: Vec<Rc<RefCell<Turtle>>>,
}
impl Turtle{
pub fn new(name: String) -> Turtle{
Turtle {name: name, children: Vec::new()}
}
pub fn add_child(&mut self, t: Rc<RefCell<Turtle>>) {
&self.children.push(t);
}
pub fn breed(mut t1: Turtle, mut t2: Turtle, name: String) -> Turtle{
let t = Turtle {name: name, children:Vec::new()};
let s = Rc::new(RefCell::new(Turtle {name: name, children:Vec::new()}));
t1.add_child(Rc::clone(&s));
t2.add_child(Rc::clone(&s));
t
}
}
Before I added the name field, it was running without any issues, but now it's not. Here's the error:
error[E0382]: use of moved value: `name`
--> src/lib.rs:18:52
|
16 | pub fn breed(mut t1: Turtle, mut t2: Turtle, name: String) -> Turtle{
| ---- move occurs because `name` has type `String`, which does not implement the `Copy` trait
17 | let t = Turtle {name: name, children:Vec::new()};
| ---- value moved here
18 | let s = Rc::new(RefCell::new(Turtle {name: name, children:Vec::new()}));
| ^^^^ value used here after move
I was unable to fix the error while satisfying these conditions:
add_child now takes in a Turtle, what I had originally, instead of a Rc<RefCell<Turtle>>
breed still has 2 turtle or &turtle parameter, and calls add_child to add to t1 and t2
There is no longer a need to call the Turtle constructor with tons of new variables twice.
The Rc RefCell paradigm is still employed.
Condition 3 is important because I have left out a bunch of fields from Turtle, and if I add them back in and keep the declarations of s and t, there will be lots of repeated code. So the question stands, how do I replace s and t with one grand unified variable that can be passed around to add_child and used for the return value of the breed function without causing any move errors? Condition 1 is not so important to me, and if add_child continues to require a Rc RefCell, so be it. Condition 4 is very important because it means the rest of my code, once I add it back in, will run smoothly. Note that the parameters of breed can be changed to &turtle if needed, although I imagine this won't be necessary.
Update: I decided to make the function return a &Turtle, but it still doesn't work.
pub fn breed<'a>(t1: &'a mut Turtle, t2: &'a mut Turtle, name: String) -> &'a Turtle{
let s = Rc::new(RefCell::new(Turtle {name: name, children:Vec::new()}));
t1.add_child(Rc::clone(&s));
t2.add_child(Rc::clone(&s));
&*s.borrow_mut()
}
Error:
error[E0515]: cannot return value referencing local variable `s`
--> src/lib.rs:20:9
|
20 | &*s.borrow_mut()
| ^^-^^^^^^^^^^^^^
| | |
| | `s` is borrowed here
| returns a value referencing data owned by the current function
error[E0515]: cannot return value referencing temporary value
--> src/lib.rs:20:9
|
20 | &*s.borrow_mut()
| ^^--------------
| | |
| | temporary value created here
| returns a value referencing data owned by the current function
What do I do now? I've exhausted all my options for what could be returned by the function, knowing it must be a &Turtle and it must point to the same turtle that s does. In other words, if t1 or t2 modifies a child, the same modification must apply to the turtle that was returned.
Update 2: The reason I need to return a Turtle or &Turtle is due to the fact I'm using the result in a different class as shown in the function below.
pub fn breed_turtles(&mut self, t1_index: usize, t2_index: usize, child_name: String) {
let n = self.size();
if t1_index>n-1 || t2_index>n-1 {
panic!("out of bounds");
}
let t = Turtle::breed(&mut self.turtles[t1_index].t.borrow_mut(),&mut self.turtles[t2_index].t.borrow_mut(),child_name);
self.add_turtle(*t);
}