How to mutate values of nested structs in Rust? - rust

I'm having trouble figuring out how to mutate nested structs. I have a Folder struct that can hold Files and other Folders inside it. I then want to be able to add new files and folders to those nested folders after creating them, but I keep running into errors.
Code:
type SubFolder = Vec<Box<Folder>>;
type Files = Vec<String>;
#[derive(Debug)]
struct Folder {
files: Files,
sub_folder: SubFolder
}
impl Folder {
pub fn new() -> Self {
Self {
files: Vec::new(),
sub_folder: Vec::new(),
}
}
pub fn add_file(&mut self, file: String) {
self.files.push(file);
}
pub fn add_folder(&mut self, dir: Box<Folder>) {
self.sub_folder.push(dir);
}
}
fn main() {
let mut folder_1 = Folder::new();
let mut folder_2 = Folder::new();
folder_1.add_folder(Box::new(folder_2));
folder_2.add_file(String::from("b.txt")); // Error
}
Error Message:
error[E0382]: borrow of moved value: `folder_2`
--> src/main.rs:32:5
|
29 | let mut folder_2 = Folder::new();
| ------------ move occurs because `folder_2` has type `Folder`, which does not implement the `Copy` trait
30 |
31 | folder_1.add_folder(Box::new(folder_2));
| -------- value moved here
32 | folder_2.add_file(String::from("b.txt")); // Error
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move
Is it even possible to do this? Or do I need to use unsafe code? Any resources or suggestions would be appreciated.

for your methods add_folder and add_file you need mut reference to self. However after folder2 has been moved you can not reference it anymore.
There are a few ways to address it.
You can use "full path".
Like so:
type SubFolder = Vec<Box<Folder>>;
type Files = Vec<String>;
#[derive(Debug)]
struct Folder {
files: Files,
sub_folder: SubFolder
}
impl Folder {
pub fn new() -> Self {
Self {
files: Vec::new(),
sub_folder: Vec::new(),
}
}
pub fn add_file(&mut self, file: String) {
self.files.push(file);
}
pub fn add_folder(&mut self, dir: Box<Folder>) {
self.sub_folder.push(dir);
}
}
fn main() {
let mut folder_1 = Folder::new();
let mut folder_2 = Folder::new();
folder_1.add_folder(Box::new(folder_2));
folder_1.sub_folder[0].add_file(String::from("b.txt")); // Ok
}
Or if you really need to reference folder2 then you have to own it multiple times, so you need Rc for multiple ownership and RefCell for interior mutability as Rc is read only
E.g.:
use std::cell::RefCell;
use std::rc::Rc;
type SubFolder = Vec<Rc<RefCell<Folder>>>;
type Files = Vec<String>;
#[derive(Debug)]
struct Folder {
files: Files,
sub_folder: SubFolder
}
impl Folder {
pub fn new() -> Self {
Self {
files: Vec::new(),
sub_folder: Vec::new()
}
}
pub fn add_file(&mut self, file: String) {
self.files.push(file);
}
pub fn add_folder(&mut self, dir: Rc<RefCell<Folder>>) {
self.sub_folder.push(dir);
}
}
fn main() {
let mut folder_1 = Folder::new();
let mut folder_2 = Rc::new((RefCell::new(Folder::new())));
folder_1.add_folder(Rc::clone(folder_2));
folder_2.borrow_mut().add_file(String::from("b.txt")); // Ok
}
Btw, with Vec you can not address subfolder or file by name. Maybe better use Hashmap?

Related

Rust Help Needed: Issue with "cannot borrow data in a `&` reference as mutable" [duplicate]

This question already has answers here:
How do I create a global, mutable singleton?
(7 answers)
Closed 3 months ago.
I am new to rust and cannot understand the issue below. I am trying to store the Trait of Animals in the vector.
My implementation is as below.
mod TestAnimal {
use crate::stack;
pub trait Animal {
fn diagnose(&self) -> Result<(), stack::service::ServiceError>;
}
pub struct Hospital {
animals: Vec<Box<dyn Animal>>,
}
static mut HOSPITAL: Hospital = Hospital { animals: Vec::new() };
impl Hospital {
pub fn add_animal(&mut self, animal: Box<dyn Animal>) {
self.animals.push(animal);
}
}
pub fn get_hospital() -> &'static Hospital {
unsafe {
return &HOSPITAL;
}
}
}
#[test]
fn test_hospital() {
pub struct Cat;
impl TestAnimal::Animal for Cat {
fn diagnose(&self) -> Result<(), stack::service::ServiceError> {
return Ok(());
}
}
TestAnimal::get_hospital().add_animal(Box::new(Cat {}));
}
The issue I am facing is as below.
error[E0596]: cannot borrow data in a `&` reference as mutable
--> src/main.rs:45:5
|
45 | TestAnimal::get_hospital().add_animal(Box::new(Cat {}));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
Looks like you are trying to mutate a static variable. Normally this isn't safe because multiple threads editing a value at the same time can cause issues. You can make it safe by wrapping the variable in a mutex. A mutex will ensure that only one thread can mutate the variable at a time.
mod test_animal {
use crate::stack;
use std::sync::Mutex;
pub trait Animal { 0 implementations
fn diagnose(&self) -> Result<(), stack::service::ServiceError>;
}
pub struct Hospital { 1 implementation
animals: Vec<Box<dyn Animal + Send>>,
}
pub static HOSPITAL: Mutex<Hospital> = Mutex::new(Hospital {
animals: Vec::new(),
});
impl Hospital {
pub fn add_animal(&mut self, animal: Box<dyn Animal + Send>) {
self.animals.push(animal);
}
}
}
#[test]
fn test_hospital() {
pub struct Cat;
impl test_animal::Animal for Cat {
fn diagnose(&self) -> Result<(), stack::service::ServiceError> {
return Ok(());
}
}
test_animal::HOSPITAL
.lock()
.unwrap()
.add_animal(Box::new(Cat {}));
}
That said, sometimes you'll find you don't actually need a static variable. Mutable static variables often make code harder to understand. You might consider doing this instead:
mod test_animal {
use crate::stack;
pub trait Animal {
fn diagnose(&self) -> Result<(), stack::service::ServiceError>;
}
pub struct Hospital {
animals: Vec<Box<dyn Animal + Send>>,
}
impl Hospital {
pub fn new() -> Self {
Self {
animals: Vec::new(),
}
}
pub fn add_animal(&mut self, animal: Box<dyn Animal + Send>) {
self.animals.push(animal);
}
}
}
#[test]
fn test_hospital() {
pub struct Cat;
impl test_animal::Animal for Cat {
fn diagnose(&self) -> Result<(), stack::service::ServiceError> {
return Ok(());
}
}
let mut hospital = test_animal::Hospital::new();
hospital.add_animal(Box::new(Cat {}));
}

"Lifetime in struct : "this value requires that `'1` must outlive `'static`

I am new to the concept of lifetime but I don't understand why the current code gives me an error
error ->
[1]: https://i.stack.imgur.com/v4Yf6.png
Code :
pub struct Folder<'a> {
pub name: &'a str,
pub contents: Vec<Box<dyn Executable>>,
pub parent: Box<Option<&'a Folder<'a>>>
}
impl<'a> Folder<'a> {
pub fn new(folder_name: &'a str, json_content: &'a Value) -> Self {
Self {
name: folder_name,
contents: Folder::get_content(json_content),
parent: Box::new(None)
}
}
fn get_content(json_content: &Value) -> Vec<Box<dyn Executable>> {
let elements_in_folder: &Vec<Value> = json_content.as_array().unwrap();
let mut contents: Vec<Box<dyn Executable>> = Vec::new();
for element in elements_in_folder.iter() {
match element["type"].as_str().unwrap() {
"folder" => {
let folder = Folder::new(
element["name"].as_str().unwrap(),
&element["content"],
);
contents.push(Box::new(folder))
}
"command" => contents.push(Box::new(Command::new(&element))),
"combo" => contents.push(Box::new(Combo::new(&element))),
_ => panic!("Folder: field type unknow"),
}
}
contents // THE ERROR IS HERE
}
}
Folder Command and Combo impl Executable
Your contents is borrowing values from inside the argument. You need to make that explicit, with a lifetime constraint.
fn get_content<'a>(json_content: &'a Value) -> Vec<Box<dyn Executable + 'a>> {
...
}
or, equivalently, you can use the anonymous lifetime. The following is equivalent to the above but shorter.
fn get_content(json_content: &Value) -> Vec<Box<dyn Executable + '_>> {
...
}

Trouble with digraphs: cannot borrow as mutable

I created a library to deal with digraphs: nodes that link (reference counted) to zero or one other nodes (as in linked lists, but in a digraph a node can be linked to by more than one node).
I am trying to use my library to create a list with a current node:
struct ListWithPointer<'a> {
pub nodes: DigraphNodeRef<String>,
pub current_node: Option<&'a mut DigraphNodeRef<String>>,
}
current_node points to a link in the list.
Now I am trying to move current node to the next element of the list (or to the beginning if the list ended):
fn next_node<'a>(this: &'a mut ListWithPointer<'a>) {
if this.current_node.is_some() {
this.current_node.iter_mut().for_each(|a| {
(*a).as_rc_mut().iter_mut()
.for_each(|rc| this.current_node = Some(&mut Arc::get_mut(rc).unwrap().next));
});
} else {
this.current_node = Some(&mut this.nodes);
}
}
but whatever I do, it fails with an error like:
error[E0500]: closure requires unique access to `this.current_node` but it is already borrowed
--> src/lib.rs:150:51
|
148 | fn next_node<'a>(this: &'a mut ListWithPointer<'a>) {
| -- lifetime `'a` defined here
149 | if this.current_node.is_some() {
150 | this.current_node.iter_mut().for_each(|a| {
| ---------------------------- ^^^ closure construction occurs here
| |
| borrow occurs here
| argument requires that `this.current_node` is borrowed for `'a`
151 | (*a).as_rc_mut().iter_mut()
152 | .for_each(|rc| this.current_node = Some(&mut Arc::get_mut(rc).unwrap().next));
| ----------------- second borrow occurs due to use of `this.current_node` in closure
Help to rewrite without errors.
Here is the library code:
use std::sync::Arc;
#[derive(Clone)]
pub struct DigraphNode<T> {
pub next: DigraphNodeRef<T>, // I made it `pub` to be able `item.next.next()` to remove an item from the middle.
data: T,
}
impl<T> DigraphNode<T> {
fn new(next: DigraphNodeRef<T>, data: T) -> Self {
Self { next, data }
}
}
pub struct DigraphNodeRef<T> {
rc: Option<Arc<DigraphNode<T>>>,
}
impl<T> DigraphNodeRef<T> {
pub fn new() -> Self {
Self {
rc: None
}
}
pub fn from_node(value: DigraphNode<T>) -> Self {
Self::from(Some(Arc::new(value)))
}
pub fn from(rc: Option<Arc<DigraphNode<T>>>) -> Self {
Self {
rc
}
}
pub fn as_rc(&self) -> &Option<Arc<DigraphNode<T>>> {
&self.rc
}
pub fn as_rc_mut(&mut self) -> &mut Option<Arc<DigraphNode<T>>> {
&mut self.rc
}
pub fn is_none(&self) -> bool {
self.rc.is_none()
}
pub fn remove(&mut self) -> bool {
if let Some(rc) = self.rc.clone() {
self.rc = rc.next.rc.clone();
true
} else {
false
}
}
pub fn prepend(&mut self, value: T) -> Self {
let new_node = DigraphNode::new(self.clone(), value);
let new_node_ref = DigraphNodeRef::from_node(new_node);
*self = new_node_ref.clone();
new_node_ref
}
pub fn node(&self) -> Option<DigraphNode<T>>
where T: Clone
{
self.rc.clone().map(|node| (*node).clone())
}
/// TODO: Should return a reference.
pub fn data(&self) -> Option<T>
where T: Clone
{
self.rc.clone().map(|node| (*node).data.clone())
}
pub fn values(self) -> DigraphNodeValuesIterator<T> {
DigraphNodeValuesIterator {
underlying: self.clone()
}
}
}
impl<T> Clone for DigraphNodeRef<T> {
fn clone(&self) -> Self {
Self { rc: self.rc.clone() }
}
}
impl<T> Iterator for DigraphNodeRef<T> {
type Item = Arc<DigraphNode<T>>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(rc) = self.rc.clone() {
self.rc = rc.next.rc.clone();
Some(rc.clone())
} else {
None
}
}
}
pub struct DigraphNodeValuesIterator<T> {
underlying: DigraphNodeRef<T>,
}
impl<T: Clone> Iterator for DigraphNodeValuesIterator<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.underlying.next().map(|node| node.data.clone())
}
}
In Rust the mutable access is ensured to be exclusive, i.e. if you hold a reference, some other code can't grab a mutable reference.
Problem is this line:
this.current_node.iter_mut().for_each(...)
It grabs a mutable access to current_node, so it can't regain it again down the line.
Not to mention that iterating over Option is a strange decision.
If you want to move current_node to a different place, I'd try to reorganize your code such that reads are separate from writes, and they are performed in a sequence, instead of trying to do it in one go:
// detach the current_node for moving
if let Some(current_node_to_move) = this.current_node.take() {
let new_current_node_ref: &mut ... = ... // find new location logic
new_current_node_ref.replace(current_node_to_move);
} else {
...
}
Here in line 1 it does a write None update to current_node via this, but immediately relinquishes the mutable reference. Line 2 does a read (search), but also grabs a mutable reference to a new location. Line 3 writes to this location.
To get the linked list implementation right, I recommend https://rust-unofficial.github.io/too-many-lists/

Struct containing reference to a file in Rust fails to borrow

Not sure what I am missing here, the lifetime is declared, therefore the struct should use the path to create the file and return a Struct with the mutable File reference for me to be able to call "write" wrapper later...
use std::path::Path;
use std::fs::File;
// use std::io::Write;
#[derive(Debug)]
pub struct Foo<'a> {
file: &'a mut File,
}
impl<'a> Foo<'a> {
pub fn new(path: &'a Path) -> Result<Self, std::io::Error> {
let mut f: &'a File = &File::create(path)?;
Ok(Self { file: &mut f })
}
//pub fn write(&self, b: [u8]) {
// self.file.write(b);
//}
}
Error:
| impl<'a> Foo<'a> {
| -- lifetime `'a` defined here
11 | pub fn new(path: &'a Path) -> Result<Self, std::io::Error> {
12 | let mut f: &'a File = &File::create(path)?;
| -------- ^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
| |
| type annotation requires that borrow lasts for `'a`
...
15 | }
| - temporary value is freed at the end of this statement
As #E_net4 mentioned, I don't want a mutable reference, yet I want to own the value. Rather than trying to play with lifetimes, I can basically just own the file and handle the whole struct as mutable when trying to write to the file!
use std::path::{ PathBuf };
use std::fs::File;
use std::io::Write;
use std::env;
#[derive(Debug)]
pub struct Foo {
file: File,
}
impl Foo {
pub fn new(path: PathBuf) -> Self {
Self {
file: File::create(path).unwrap(),
}
}
pub fn write(&mut self, b: &[u8]) -> Result<usize, std::io::Error> {
self.file.write(b)
}
}
fn main() {
let mut tmp_dir = env::temp_dir();
tmp_dir.push("foo23");
let mut f = Foo::new(tmp_dir);
f.write(b"test2").unwrap();
}

Storing types in a HashMap to dynamically instantiate them

I am trying to store structs in a HashMap keyed by string so that I can later create new objects by string. Think of a REST API where clients can get the server to instantiate a specific object by supplying a name.
use std::collections::HashMap;
struct MyStruct;
impl MyStruct {
pub fn new() -> Self {
Self {}
}
}
struct MyOtherStruct;
impl MyOtherStruct {
pub fn new() -> Self {
Self {}
}
}
fn main() {
let mut h = HashMap::new();
h.insert("MyStruct", MyStruct);
h.insert("MyOtherStruct", MyOtherStruct);
// This is pseudo-code
let obj = h.get("MyStruct").unwrap()::new();
}
As I expected, this doesn't work due to syntax errors:
error: expected one of `.`, `;`, `?`, or an operator, found `::`
--> src/main.rs:25:41
|
25 | let obj = h.get("MyStruct").unwrap()::new();
| ^^ expected one of `.`, `;`, `?`, or an operator here
My second attempt was to store a reference to the new method of each struct instead of the types themselves.
use std::collections::HashMap;
struct MyStruct;
impl MyStruct {
pub fn new() -> Self {
Self {}
}
}
struct MyOtherStruct;
impl MyOtherStruct {
pub fn new() -> Self {
Self {}
}
}
fn main() {
let mut h = HashMap::new();
h.insert("MyStruct", &MyStruct::new);
h.insert("MyOtherStruct", &MyOtherStruct::new);
let obj = h.get("MyStruct").unwrap()();
}
This fails because the fn items have different types and can't be stored in the same HashMap:
error[E0308]: mismatched types
--> src/main.rs:22:31
|
22 | h.insert("MyOtherStruct", &MyOtherStruct::new);
| ^^^^^^^^^^^^^^^^^^^ expected fn item, found a different fn item
|
= note: expected type `&fn() -> MyStruct {MyStruct::new}`
found type `&fn() -> MyOtherStruct {MyOtherStruct::new}`
Since I'm pretty new to Rust, I'm out of ideas. How can I solve this problem?
This is ultimately fundamentally impossible. In Rust, local variables are stored on the stack, which means that they have to have a fixed size, known at compile time. Your construction requires the size of the value on the stack to be determined at runtime.
The closest alternative is to move to trait objects, which introduce a layer of indirection:
use std::collections::HashMap;
trait NewThing {
fn new(&self) -> Box<Thing>;
}
trait Thing {}
struct MyStruct;
impl NewThing for MyStruct {
fn new(&self) -> Box<Thing> {
Box::new(Self {})
}
}
impl Thing for MyStruct {}
struct MyOtherStruct;
impl NewThing for MyOtherStruct {
fn new(&self) -> Box<Thing> {
Box::new(Self {})
}
}
impl Thing for MyOtherStruct {}
fn main() {
let mut h: HashMap<_, Box<NewThing>> = HashMap::new();
h.insert("MyStruct", Box::new(MyStruct));
h.insert("MyOtherStruct", Box::new(MyOtherStruct));
let obj = h["MyStruct"].new();
}
You will find this pattern out in the world, such as in hyper's NewService.
what is [the value of &self of method new] when calling h["MyStruct"].new()
It's an instance of MyStruct or MyOtherStruct. The only reason that the same type can implement both traits is because there's no real unique state for the "factory" and the "instance". In more complicated implementations, these would be two different types.
Using the same type is common for such cases as sharing a reference-counted value.
See also:
Is it possible to have a constructor function in a trait?
Here is a more complex example of #Shepmaster's solution, using different types for Factories and the objects themselves:
use std::collections::HashMap;
trait NewThing {
fn new(&self) -> Box<Thing>;
}
trait Thing {
fn execute(&mut self);
}
// MyStruct
struct MyStructFactory;
impl NewThing for MyStructFactory {
fn new(&self) -> Box<Thing> {
Box::new(MyStruct {test: 12, name: "Test".into()})
}
}
struct MyStruct {
test: i32,
name: String
}
impl Thing for MyStruct {
fn execute(&mut self) {
self.test+=1;
println!("MyStruct {} {}", self.test, self.name);
}
}
// MyOtherStruct
struct MyOtherStructFactory;
impl NewThing for MyOtherStructFactory {
fn new(&self) -> Box<Thing> {
Box::new(MyOtherStruct {my_member: 1})
}
}
struct MyOtherStruct {
my_member: u32
}
impl Thing for MyOtherStruct {
fn execute(&mut self) { println!("MyOtherStruct.my_member: {}", self.my_member); }
}
fn main() {
let mut h: HashMap<_, Box<NewThing>> = HashMap::new();
h.insert("MyStruct", Box::new(MyStructFactory));
h.insert("MyOtherStruct", Box::new(MyOtherStructFactory));
h["MyStruct"].new().execute();
h["MyOtherStruct"].new().execute();
}
You could use std::any::Any to erase the type of the entry. They use Any::downcast<T> to check if the entry at the location matches your type, and get a Ok(Box<T>)

Resources