I am trying to initialise an array of structs in Rust:
enum Direction {
North,
East,
South,
West,
}
struct RoadPoint {
direction: Direction,
index: i32,
}
// Initialise the array, but failed.
let data = [RoadPoint { direction: Direction::East, index: 1 }; 4];
When I try to compile, the compiler complains that the Copy trait is not implemented:
error[E0277]: the trait bound `main::RoadPoint: std::marker::Copy` is not satisfied
--> src/main.rs:15:16
|
15 | let data = [RoadPoint { direction: Direction::East, index: 1 }; 4];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `main::RoadPoint`
|
= note: the `Copy` trait is required because the repeated element will be copied
How can the Copy trait be implemented?
You don't have to implement Copy yourself; the compiler can derive it for you:
#[derive(Copy, Clone)]
enum Direction {
North,
East,
South,
West,
}
#[derive(Copy, Clone)]
struct RoadPoint {
direction: Direction,
index: i32,
}
Note that every type that implements Copy must also implement Clone. Clone can also be derived.
Just prepend #[derive(Copy, Clone)] before your enum.
If you really want, you can also
impl Copy for MyEnum {}
The derive-attribute does the same thing under the hood.
Related
How to clone a vector with struct items in Rust.
I've tried to .to_vec() it, but it seems that I can't because I'm using structs.
struct Abc {
id: u32,
name: String
}
let mut vec1: Vec<Abc> = vec![];
let item1 = Abc {
id: 1,
name: String::from("AlgoQ")
}
vec1.push(item1)
let vec2 = vec1.to_vec();
Error:
the trait bound `blabla::Abc: Clone` is not satisfied
the trait `Clone` is not implemented for `blabla::Abc`rustc(E0277)
To clone a Vec the Type inside the Vec also has to implement the Clone trait.
The easiest way to do this is to use the derive macro as seen here.
In your example you'd just have to add #[derive(Clone)] above your Abc struct.
You can do this for objects of structs as you do it for primitives but the struct of the elements of the vector must implement Clone trait to make the vector cloneable.
Exactly as the compiler says
You can use #[derive()] macro easily to implement the trait, unless you don't want to use a custom implementation, as follows
#[derive(Clone)]
struct Abc {
id: u32,
name: String
}
fn main(){
let mut vec1= vec![];
let item1 = Abc {
id: 1,
name: String::from("AlgoQ"),
};
vec1.push(item1);
let vec2 = vec1.clone();
}
Demo
This is a vastly simplified example of the issue I'm running into, but given a trait Thing which implements Ord, and a struct Object which implements Thing, I have the following struct:
pub struct MyStruct<'a> {
my_things: HashMap<i32, Vec<Box<dyn Thing + 'a>>>
}
impl<'a> MyStruct<'a> {
pub fn new() -> MyStruct<'a> {
MyStruct {
my_things: HashMap::new()
}
}
pub fn add_object(&mut self, key: i32, obj: Object) {
if !self.my_things.contains_key(&key) {
self.my_things.insert(key, Vec::new());
}
let new_thing: Box<dyn Thing> = Box::new(obj);
let things = self.my_things.get_mut(&key).unwrap();
things.push(new_thing);
things.sort();
}
}
It essentially takes a key and an Object, and adds the object to a HashMap of Vecs using the given key. I know this isn't the optimal way to do this but I wanted to keep it simpler for illustration.
The compiler complains on the call to things.sort() with the following error:
error[E0308]: mismatched types
--> src/main.rs:58:16
|
58 | things.sort();
| ^^^^ lifetime mismatch
|
= note: expected trait `Ord`
found trait `Ord`
note: the lifetime `'a` as defined on the impl at 42:6...
--> src/main.rs:42:6
|
42 | impl<'a> MyStruct<'a> {
| ^^
= note: ...does not necessarily outlive the static lifetime
Playground link
If I remove all of the 'a lifetimes in this example, the code will compile. But for my actual use case, I need to allow non-static lifetimes.
Can someone explain what's going on here? Does sort() really require the Vec to contain items with static lifetimes? If so why?
Is there a good workaround?
You only implemented Ord for dyn Thing + 'static. The 'static lifetime bound is inferred if you don't explicitly specify any other lifetime bound. To implement Ord for non-'static dyn Things you need to introduce and use a generic lifetime parameter, e.g. 'a, in your implementations. Updated compiling example:
use std::collections::HashMap;
use std::cmp;
pub trait Thing {
fn priority(&self) -> i32;
}
impl<'a> PartialEq for dyn Thing + 'a { // 'a added here
fn eq(&self, other: &Self) -> bool {
self.priority() == other.priority()
}
}
impl<'a> PartialOrd for dyn Thing + 'a { // 'a added here
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
self.priority().partial_cmp(&other.priority())
}
}
impl<'a> Eq for dyn Thing + 'a {} // 'a added here
impl<'a> Ord for dyn Thing + 'a { // 'a added here
fn cmp(&self, other: &Self) -> cmp::Ordering{
self.priority().cmp(&other.priority())
}
}
pub struct Object {
priority: i32,
}
impl Thing for Object {
fn priority(&self) -> i32 {
self.priority
}
}
pub struct MyStruct<'a> {
my_things: HashMap<i32, Vec<Box<dyn Thing + 'a>>>
}
impl<'a> MyStruct<'a> {
pub fn new() -> MyStruct<'a> {
MyStruct {
my_things: HashMap::new()
}
}
pub fn add_object(&mut self, key: i32, obj: Object) {
if !self.my_things.contains_key(&key) {
self.my_things.insert(key, Vec::new());
}
let new_thing: Box<dyn Thing> = Box::new(obj);
let things = self.my_things.get_mut(&key).unwrap();
things.push(new_thing);
things.sort();
}
}
fn main() {
let _test = MyStruct::new();
}
playground
From the Default Trait Object Lifetimes section of the Lifetime Elision chapter of the Rust Reference (emphasis mine):
If the trait object is used as a type argument of a generic type then the containing type is first used to try to infer a bound.
If there is a unique bound from the containing type then that is the default
If there is more than one bound from the containing type then an explicit bound must be specified
If neither of those rules apply, then the bounds on the trait are used:
If the trait is defined with a single lifetime bound then that bound is used.
If 'static is used for any lifetime bound then 'static is used.
If the trait has no lifetime bounds, then the lifetime is inferred in expressions and is 'static outside of expressions.
In this question someone commented that you could use PhantomData to add a lifetime bound to a raw pointer inside a struct. I thought I'd try doing this on an existing piece of code I've been working on.
Here's our (minimised) starting point. This compiles (playground):
extern crate libc;
use libc::{c_void, free, malloc};
trait Trace {}
struct MyTrace {
#[allow(dead_code)]
buf: *mut c_void,
}
impl MyTrace {
fn new() -> Self {
Self {
buf: unsafe { malloc(128) },
}
}
}
impl Trace for MyTrace {}
impl Drop for MyTrace {
fn drop(&mut self) {
unsafe { free(self.buf) };
}
}
trait Tracer {
fn start(&mut self);
fn stop(&mut self) -> Box<Trace>;
}
struct MyTracer {
trace: Option<MyTrace>,
}
impl MyTracer {
fn new() -> Self {
Self { trace: None }
}
}
impl Tracer for MyTracer {
fn start(&mut self) {
self.trace = Some(MyTrace::new());
// Pretend the buffer is mutated in C here...
}
fn stop(&mut self) -> Box<Trace> {
Box::new(self.trace.take().unwrap())
}
}
fn main() {
let mut tracer = MyTracer::new();
tracer.start();
let _trace = tracer.stop();
println!("Hello, world!");
}
I think that the problem with the above code is that I could in theory move the buf pointer out of a MyTrace and use if after the struct has died. In this case the underlying buffer will have been freed due to the Drop implementation.
By using a PhantomData we can ensure that only references to buf can be obtained, and that the lifetimes of those references are bound to the instances of MyTrace from whence they came.
We can proceed like this (playground):
extern crate libc;
use libc::{c_void, free, malloc};
use std::marker::PhantomData;
trait Trace {}
struct MyTrace<'b> {
#[allow(dead_code)]
buf: *mut c_void,
_phantom: PhantomData<&'b c_void>,
}
impl<'b> MyTrace<'b> {
fn new() -> Self {
Self {
buf: unsafe { malloc(128) },
_phantom: PhantomData,
}
}
}
impl<'b> Trace for MyTrace<'b> {}
impl<'b> Drop for MyTrace<'b> {
fn drop(&mut self) {
unsafe { free(self.buf) };
}
}
trait Tracer {
fn start(&mut self);
fn stop(&mut self) -> Box<Trace>;
}
struct MyTracer<'b> {
trace: Option<MyTrace<'b>>,
}
impl<'b> MyTracer<'b> {
fn new() -> Self {
Self { trace: None }
}
}
impl<'b> Tracer for MyTracer<'b> {
fn start(&mut self) {
self.trace = Some(MyTrace::new());
// Pretend the buffer is mutated in C here...
}
fn stop(&mut self) -> Box<Trace> {
Box::new(self.trace.take().unwrap())
}
}
fn main() {
let mut tracer = MyTracer::new();
tracer.start();
let _trace = tracer.stop();
println!("Hello, world!");
}
But this will give the error:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:53:36
|
53 | Box::new(self.trace.take().unwrap())
| ^^^^^^
|
note: first, the lifetime cannot outlive the lifetime 'b as defined on the impl at 46:1...
--> src/main.rs:46:1
|
46 | impl<'b> Tracer for MyTracer<'b> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...so that the types are compatible:
expected std::option::Option<MyTrace<'_>>
found std::option::Option<MyTrace<'b>>
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the expression is assignable:
expected std::boxed::Box<Trace + 'static>
found std::boxed::Box<Trace>
I have three sub-questions:
Did I understand the motivation for PhantomData in this scenario correctly?
Where is 'static coming from in the error message?
Can this be made to work without changing the interface of stop? Specifically, without adding a lifetime to the return type?
I'm going to ignore your direct question because I believe you arrived at it after misunderstanding several initial steps.
I could in theory move the buf pointer out of a MyTrace and use if after the struct has died
Copy the pointer, not move it, but yes.
By using a PhantomData we can ensure that only references to buf can be obtained
This is not true. It is still equally easy to get a copy of the raw pointer and misuse it even when you add a PhantomData.
Did I understand the motivation for PhantomData in this scenario correctly?
No. PhantomData is used when you want to act like you have a value of some type without actually having it. Pretending to have a reference to something is only useful when there is something to have a reference to. There's no such value to reference in your example.
The Rust docs say something about raw pointers and PhantomData, but I perhaps got it wrong
That example actually shows my point well. The Slice type is intended to behave as if it has a reference to the Vec that it's borrowed from:
fn borrow_vec<'a, T>(vec: &'a Vec<T>) -> Slice<'a, T>
Since this Slice type doesn't actually have a reference, it needs a PhantomData to act like it has a reference. Note that the lifetime 'a isn't just made up out of whole cloth — it's related to an existing value (the Vec). It would cause memory unsafety for the Slice to exist after the Vec has moved, thus it makes sense to include a lifetime of the Vec.
why the commenter in the other question suggested I use PhantomData to improve the type safety of my raw pointer
You can use PhantomData to improve the safety of raw pointers that act as references, but yours doesn't have some existing Rust value to reference. You can also use it for correctness if your pointer owns some value behind the reference, which yours seemingly does. However, since it's a c_void, it's not really useful. You'd usually see it as PhantomData<MyOwnedType>.
Where is 'static coming from in the error message?
Why is adding a lifetime to a trait with the plus operator (Iterator<Item = &Foo> + 'a) needed?
I'm having a lot of fun playing around with Rust having been a C# programmer for a long time but I have a question around reflection. Maybe I don't need reflection in this case but given that Rust is strongly typed I suspect I do (I would definitely need it in good ol' C#, bless its cotton socks).
I have this situation:
use std::collections::HashMap;
fn invoke_an_unknown_function(
hashmap: HashMap<String, String>,
// Something to denote a function I know nothing about goes here
) {
// For each key in the hash map, assign the value
// to the parameter argument whose name is the key
// and then invoke the function
}
How would I do that? I'm guessing I need to pass in some sort of MethodInfo as the second argument to the function and then poke around with that to get the arguments whose name is the key in the hash map and assign the values but I had a look around for the reflection API and found the following pre-Rust 1.0 documentation:
Module std::reflect
Module std::repr
[rust-dev] Reflection system
None of these give me enough to go on to get started. How would I implement the function I describe above?
Traits are the expected way to implement a fair amount of what reflection is (ab)used for elsewhere.
trait SomeInterface {
fn exposed1(&self, a: &str) -> bool;
fn exposed2(&self, b: i32) -> i32;
}
struct Implementation1 {
value: i32,
has_foo: bool,
}
impl SomeInterface for Implementation1 {
fn exposed1(&self, _a: &str) -> bool {
self.has_foo
}
fn exposed2(&self, b: i32) -> i32 {
self.value * b
}
}
fn test_interface(obj: &dyn SomeInterface) {
println!("{}", obj.exposed2(3));
}
fn main() {
let impl1 = Implementation1 {
value: 1,
has_foo: false,
};
test_interface(&impl1);
}
I have roughly the following code:
let val = util::replace(&mut self.some_field[i], self.some_method());
It fails with the following message:
unrelated.rs:61:65: 61:70 error: cannot borrow `*self` as immutable because it is also borrowed as mutable
unrelated.rs:61 let val = util::replace(&mut self.some_field[i], self.some_method());
^~~~~
unrelated.rs:61:36: 61:62 note: second borrow of `*self` occurs here
unrelated.rs:61 let val = util::replace(&mut self.some_field[i], self.some_method());
^~~~~~~~~~~~~~~~~~~~~~~
I can fix this by the following code:
let temp = self.some_method();
let val = util::replace(&mut self.some_field[i], temp);
But why does it fail? The scopes in which mutable and immutable pointers are taken are distinct, they are different expressions. It looks like kind of bug to me, but I just want to make sure that I'm not missing something here.
By introducing temp you've changed computation order: you first computed some_method(), then released self, and then got a mutable reference to some_field of self.
Rust does not allow holding mutable reference along with any other reference (mutable or immutable). See simpler example:
struct Foo {
a: int
}
impl Foo {
fn ff(&self) -> int { 1 }
}
fn fff(a: int, foo: &mut int) { }
fn ggg(foo: &mut int, a: int) { }
fn main() {
let mut foo = Foo { a: 0 };
fff(foo.ff(), &mut foo.a); // this call is valid
ggg(&mut foo.a, foo.ff()); // this is not
}
This is a bug: #6268.
It is because the borrow checker doesn't account for nested method calls properly yet: the nested calls should be equivalent to the code with the temporary (and thus, should be valid).