I have the following struct and when I try to call assert_eq!() on an instance of this struct I get a stack overflow due to the circular reference. I tried replacing Rc in the parent with Weak but I get the error: binary operation == cannot be applied to type Option<std::rc::Weak<std::cell::RefCell<DiskItem>>>. Is there a way to compare a structure like the one I have?
#[derive(PartialEq, Debug)]
pub struct Directory {
parent: Option<Weak<RefCell<DiskItem>>>,
children: HashMap<String, Rc<RefCell<DiskItem>>>,
}
Related
This question already has answers here:
How do I implement Copy and Clone for a type that contains a String (or any type that doesn't implement Copy)?
(2 answers)
Closed 12 months ago.
Hi I have folowing code:
#[derive(Copy, Clone, Debug)]
pub struct PriceCheckerState {
settings: Settings,
prev_notification: Option<Notification>,
}
#[derive(Copy, Clone, Debug)]
pub struct Settings {
threshold: f32,
notifications_disabled: bool,
}
#[derive(Clone, Debug)]
pub struct Notification {
gain: f32,
user_ids: Vec<f32>,
}
And I want to copy state like:
let updatedState = State {
settings: updatedSettings
..state
};
It fails that struct Notification has not defined copy makro, if I add it, then it complains that Vec has no defined copy. I understand that Vec has only clone defined. Is there any hack how to make a copy of struct with Vec (even if this Vec would be cloned)? Thanks.
Copy is used only for simple bitwise copies, i.e. the ones which can be implemented as mere memcpy. If any component of the type can't be copied this way (and Vec certainly can't), the whole struct is forced to be not Copy.
What you seem to want is an explicit call to clone whenever your state semantically should be copied:
let updatedState = State {
settings: updatedSettings,
..state.clone(),
};
pub struct Server {
devices: Vec<Device>,
}
pub struct Device {
configuration: Configuration,
}
pub enum Configuration {
Gradient {
stops: Vec<String>,
brightness: f32,
duration: i32,
random_starting_point: bool,
},
}
I want to update the configurations of certain devices dynamically through the method:
fn update_configuration(&mut self, devices: Vec<Device>, configuration: Configuration) {
self.devices
.iter_mut()
.filter(|device| devices.contains(device.get_id()))
.for_each(|device| {
(*device).configuration = configuration;
});
}
The compiler outputs:
error[E0507]: cannot move out of `configuration`, a captured variable in an `FnMut` closure
device.update_configuration(configuration);
^^^^^^^^^^^^^ move occurs because `configuration` has type `device::Configuration`, which does not implement the `Copy` trait
And since I have a Vec<String> in that enum value I can't implement the Copy trait. I do have a basic understanding of memory management (stack, heap) and pointers but I can't quite wrap my head around it completely.
My questions
How do I achieve such a field change?
Is this the idiomatic way to update such a field in a struct?
In Rust every piece of data can have at most 1 unique owner. You're taking a single instance of Configuration and trying to share it across potentially multiple Devices. The simplest way to solve your problem would be to derive an implementation of Clone which will allow you to make clones of the Configuration enum whenever you try to share it.
#[derive(Clone)]
pub enum Configuration {}
And then clone it in your loop:
self.devices
.iter_mut()
.filter(|device| devices.contains(device.get_id()))
.for_each(|device| {
(*device).configuration = configuration.clone();
});
Note: this will give a unique clone of Configuration to every Device which is what I'm assuming you want.
I have a vector of boxes of some trait core::Object objects:
pub struct Packfile<'a> {
pub version: u32,
pub objects: Vec<Box<core::Object + 'a>>,
...
Now, I want one method of Packfile to return one of those objects optionally: -> Option<Box<core::Object + 'a>>. So, having i as a reference to the index I want, I return this:
Some(self.objects[*i])
OK, this doesn't work because I'm moving the box outside of the vec. Makes sense. Let's clone it (core::Object inherits from Clone).
Some(self.objects[*i].clone())
Now, here is what I don't understand. self.objects[*i] is a box, and clone() on boxes do this: impl<T> Clone for Box<T> where T: Clone { fn clone(&self) -> Box<T>; } so clone() should be giving me a box, right? But I get this error:
src/packfile/mod.rs:190:20: 190:44 error: mismatched types:
expected `Box<core::Object + 'a>`,
found `core::Object + 'a`
(expected box,
found trait core::Object)
src/packfile/mod.rs:190 Some(self.objects[*i].clone()),
^~~~~~~~~~~~~~~~~~~~~~~~
So I don't get why I'm getting a T and not a Box<T> out of clone().
Can you help me?
If you're fine with just a reference to the object, you can do something like:
Some(&self.objects[*i])
You can even implement Index to be able to leverage the indexing operator, so you can do some_packfile[3].
So I don't get why I'm getting a T and not a Box out of clone().
Methods also do auto deref. I don't know what a core::Object is, but if it implements Clone, that's why, I'd bet.
Okay, so I am just starting learn a little bit of Rust and I am running to a pretty simple problem. I have a recursive type like this:
struct Tree {
root : i32,
children : Box<[Option<Tree> ; 100]>
}
Later, when I was trying to initialize Tree
hex.rs:30:29: 30:40 error: the trait `core::marker::Copy` is not implemented for the type `Tree` [E0277]
hex.rs:30 children : Box::new([None; 100])
^~~~~~~~~~~
error: aborting due to previous error
So, I added
#[derive(Copy)]
before the struct definition, but I got this error:
hex.rs:8:10: 8:14 error: the trait `Copy` may not be implemented for this type; field `children` does not implement `Copy` [E0204]
hex.rs:8 #[derive(Copy)]
^~~~
note: in expansion of #[derive]
hex.rs:8:1: 8:16 note: expansion site
error: aborting due to previous error
I am not entirely sure where to go from here. Is there an easy way to derive traits for recursive data types?
The problem is that Box doesn't support Copy. Copy states:
Types that can be copied by simply copying bits
However, a Box contains pointers to memory, and that memory will not be copied when you just copy the bits of the pointer.
When you are constructing your array, Rust only knows that you are going to put an Option in there. There isn't a way to have a enum only half-implement a trait.
Do you need to use a fixed-size array? Perhaps this would work better:
struct Tree {
root : i32,
children : Vec<Tree>
}
Your constructor can then use Vec::with_capacity:
impl Tree {
fn new(root: i32) -> Tree {
Tree { root: root, children: Vec::with_capacity(100) }
}
}
I'm afraid you won't be able to use static arrays and recursive types like that without unsafe. The reason is that array initializers require the array element type to be Copy because they initialize all elements with bytewise copies of the initial element, and your type can't be Copy because it contains Box, which is the only safe way to allow recursive types in Rust (well, there are also Vec and other similar containers, but they also need a heap allocation).
If you are not afraid of allocations, you can just as well use Vec:
struct Tree {
root: i32,
children: Vec<Tree>
}
Then the initialization could look like
Tree {
root: 0,
children: vec![]
}
The code looks like this:
// Simplified
pub trait Field: Send + Sync + Clone {
fn name(&self);
}
#[deriving(Clone)]
pub enum Select {
SelectOnly(Vec<Rc<Field>>),
SelectAll
}
The error is:
the trait `core::kinds::Sized` is not implemented for the type `Field+'static`
Is there any other way to have the vector with reference-counted immutable objects of trait type?
I suppose that I can rewrite the code like this:
#[deriving(Clone)]
pub enum Select {
SelectOnly(Vec<Rc<Box<Field>>>),
SelectAll
}
Is it the right way?
It is possible to create an trait object with an Rc as of Rust 1.1. This compiles:
use std::rc::Rc;
trait Field: Send + Sync {
fn name(&self);
}
enum Select {
Only(Vec<Rc<Field>>),
All,
}
// ---
struct Example;
impl Field for Example {
fn name(&self) {}
}
fn main() {
let fields: Vec<Rc<Field>> = vec![Rc::new(Example)];
Select::Only(fields);
}
Note that your original example used Clone, but you cannot make such a trait into a trait object because it is not object safe. I've removed it to answer the question.
I also removed the redundancy of the enum variant names.
I believe that it should be possible with DST, but Rust is not there just yet. The major motivation for DST was exactly the desire to use trait objects with any kind of smart pointer. As far as I know, this should be possible by 1.0 release.
As a temporary workaround, indeed, you can use Rc<Box<T>>, though this kind of double indirection is unfortunate.
It will be possible after #18248 and #16918.