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(),
};
Related
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>>>,
}
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.
This question already has answers here:
Is there a way other than traits to add methods to a type I don't own?
(2 answers)
How can I add new methods to Iterator?
(1 answer)
Closed 4 years ago.
I have a struct that is used by different functions. Instead of passing the struct as input to the different functions, I think I can implement the struct with all the functions that need to access it. However, there are certain fixed basic functions that I want to provide so that whenever the struct is created, I don't have to implement the same set of functions over and over again.
Put in another way, what I really want is the struct inheritance: I have certain set of methods associated with struct and user can add their custom functions to struct and allow them to access the data contained in data. Is there anyway able to do so?
Concretely, suppose I have a struct called AppContext and the fixed set of functions are new and bdev_name:
pub struct AppContext {
bdev: *mut raw::spdk_bdev,
bdev_desc: *mut raw::spdk_bdev_desc,
bdev_io_channel: *mut raw::spdk_io_channel,
buff: *mut c_char,
bdev_name: *const c_char,
}
impl AppContext {
pub fn new() -> Self {
let context: AppContext;
unsafe {
context = mem::uninitialized();
}
context
}
pub fn bdev_name(&mut self, name: &str) {
self.bdev_name = CString::new(name)
.expect("Couldn't create a string")
.into_raw()
}
}
Now, when I use this struct, I do:
let mut context = AppContext::new();
context.bdev_name("Nvme0n1");
I want to add one extra function (say end()) that can work on the data within the context struct. However, end() is very domain specific function and needed in a specific module, and thus it's not a good idea to implement as part of the context struct.
Is there any way I can workaround the issue (i.e. add custom function to predefined struct)?
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.
In Rust, tuple structs with only one field can be created like the following:
struct Centimeters(i32);
I want to do basic arithmetic with Centimeters without extracting their "inner" values every time with pattern matching, and without implementing the Add, Sub, ... traits and overloading operators.
What I want to do is:
let a = Centimeters(100);
let b = Centimeters(200);
assert_eq!(a + a, b);
is there a way to do it without extracting their "inner" values every time with pattern matching, and without implementing the Add, Sub, ... traits and overloading operators?
No, the only way is to implement the traits manually. Rust doesn't have an equivalent to the Haskell's GHC extension GeneralizedNewtypeDeriving which allows deriving on wrapper types to automatically implement any type class/trait that the wrapped type implements (and with the current set-up of Rust's #[derive] as a simple AST transformation, implementing it like Haskell is essentially impossible.)
To abbreviate the process, you could use a macro:
use std::ops::{Add, Sub};
macro_rules! obvious_impl {
(impl $trait_: ident for $type_: ident { fn $method: ident }) => {
impl $trait_<$type_> for $type_ {
type Output = $type_;
fn $method(self, $type_(b): $type_) -> $type_ {
let $type_(a) = self;
$type_(a.$method(&b))
}
}
}
}
#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Debug)]
pub struct Centimeters(i32);
obvious_impl! { impl Add for Centimeters { fn add } }
obvious_impl! { impl Sub for Centimeters { fn sub } }
#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Debug)]
pub struct Inches(i32);
obvious_impl! { impl Add for Inches { fn add } }
obvious_impl! { impl Sub for Inches { fn sub } }
fn main() {
let a = Centimeters(100);
let b = Centimeters(200);
let c = Inches(10);
let d = Inches(20);
println!("{:?} {:?}", a + b, c + d); // Centimeters(300) Inches(30)
// error:
// a + c;
}
playpen
I emulated the normal impl syntax in the macro to make it obvious what is happening just by looking at the macro invocation (i.e. reducing the need to look at the macro definition), and also to maintain Rust's natural searchability: if you're looking for traits on Centimeters just grep for for Centimeters and you'll find these macro invocations along with the normal impls.
If you are accessing the contents of the Centimeters type a lot, you could consider using a proper struct with a field to define the wrapper:
struct Centimeters { amt: i32 }
This allows you to write self.amt instead of having to do the pattern matching. You can also define a function like fn cm(x: i32) -> Centimeters { Centimeters { amt: x } }, called like cm(100), to avoid the verbosity of constructing a full struct.
You can also access the inner values of a tuple struct using the .0, .1 syntax.
I made the derive_more crate for this problem. It can derive lots of traits for structs of which the elements implement them.
You need to add derive_more to your Cargo.toml. Then you can write:
#[macro_use]
extern crate derive_more;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Add)]
struct Centimeters(i32);
fn main() {
let a = Centimeters(100);
let b = Centimeters(200);
assert_eq!(a + a, b);
}
For Rust version 1.10.0, it seems to me that type aliases would perfectly fit the situation you are describing. They simply give a type a different name.
Let's say all centimeters are u32s. Then I could just use the code
type Centimeters = u32;
Any trait that u32 has, Centimeters would automatically have. This doesn't eliminate the possibility of adding Centimeters to Inches. If you're careful, you wouldn't need different types.