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
I am struggling to make this work:
trait HasVoice: PartialEq + Eq + Hash {
fn talk(self: &Self) {}
}
#[derive(PartialEq, Hash, Eq)]
struct Duck {
name: String,
}
#[derive(PartialEq, Hash, Eq)]
struct Dog {
breed: String,
}
impl HasVoice for Duck {
fn talk(self: &Self) {
println!("duck quack!")
}
}
impl HasVoice for Dog {
fn talk(self: &Self) {
println!("dog bark!")
}
}
fn test() {
let duck: Duck = Duck {
name: "duckie".to_string(),
};
let dog: Dog = Dog {
breed: "labrador".to_string(),
};
let mut quack_set: HashSet<Box<dyn HasVoice>> = HashSet::new();
quack_set.insert(duck);
quack_set.insert(dog);
}
I am getting:
the trait `HasVoice` cannot be made into an object
`HasVoice` cannot be made into an objectrustcClick for full compiler diagnostic
main.rs(59, 17): for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
TL;DR: You didn't specify how to compare Dogs and Ducks, so the compiler is complaining at you. You have to provide a way for them to be compared.
The solution to this is way more complicated than I was expecting, and probably isn't a good idea. You should just use an enum Voiced { Dog(Dog), Duck(Duck) } instead.
The problem
If you view the full compiler diagnostics, you will see the following:
error[E0038]: the trait `HasVoice` cannot be made into an object
--> src/lib.rs:39:36
|
39 | let mut quack_set: HashSet<Box<dyn HasVoice>> = HashSet::new();
| ^^^^^^^^^^^^ `HasVoice` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> src/lib.rs:4:17
|
4 | trait HasVoice: PartialEq + Eq + Hash {
| -------- ^^^^^^^^^ ...because it uses `Self` as a type parameter
| |
| this trait cannot be made into an object...
You can see there's a problem with PartialEq. But what is it?
What's the big deal with PartialEq?
The problem is that PartialEq is declared as PartialEq<Rhs = Self>, which defaults to the trait PartialEq<Self> if you don't specify a type parameter. In other words, PartialEq by default provides the comparison of a type with itself.
Consider the following code:
let duck: &dyn HasVoice = &Duck { /* ... */ };
let dog: &dyn HasVoice = &Dog { /* ... */ };
println!("{}", dog == duck);
What do you expect the outcome to be?
Well, dog == duck is equivalent to dog.eq(duck), right? So Rust will look up the vtable for dog, see that dog does in fact have an eq method of type fn eq(&self, rhs: Dog), and... wait a second. The rhs is explicitly not a Dog, it's a &dyn HasVoice, which contains a pointer to the type Duck. So there's absolutely no way you can call eq on these two types.
This issue was discovered back in 2015, and the decided solution was to ban any Self parameters in supertraits that aren't &self. This means that PartialEq<Self> cannot be used to compare two Box<dyn HasVoice> types.
So then what?
How do I fix this?
Before we know how to fix the issue, we need to know first:
How do we compare Dog and Duck?
Do they compare unequal always? Equal always? Something more exotic? The compiler doesn't know, only you do, so you should specify it. What should the answer be?
Let's say that Dogs and Ducks are always unequal. This is probably what most people expect from dogs and ducks in real life. How do we achieve that?
Well, you can do a bunch of trait machinery manually, but the easiest way is to use the dyn_partial_eq crate.
Here's how:
use dyn_partial_eq::*;
#[dyn_partial_eq]
trait HasVoice {
fn talk(&self);
}
#[derive(DynPartialEq, PartialEq, Eq, Hash)]
struct Duck {
name: String,
}
#[derive(DynPartialEq, PartialEq, Eq, Hash)]
struct Dog {
breed: String,
}
Then PartialEq works properly, right? So all is good?
Well, no. We forgot about Hash.
How do we implement Hash?
The Hash trait is not object-safe. If you add it to the trait requirements, you'll just get a compile error. This is because Hash::hash is a generic function, so it can't be put in a vtable.
We can get around this by making a DynHash trait that isn't generic and instead takes a &mut dyn reference. Here's how you might do it:
trait DynHash {
fn dyn_hash(&self, state: &mut dyn Hasher);
}
impl<H: Hash + ?Sized> DynHash for H {
fn dyn_hash(&self, mut state: &mut dyn Hasher) {
self.hash(&mut state);
}
}
#[dyn_partial_eq]
trait HasVoice: DynHash {
fn talk(&self);
}
impl Hash for dyn HasVoice {
fn hash<H: Hasher>(&self, state: &mut H) {
self.dyn_hash(state)
}
}
impl Eq for Box<dyn HasVoice> {} // required for HashSet
That's all you need.
The final code
use std::hash::{Hash, Hasher};
use std::collections::HashSet;
use dyn_partial_eq::*;
trait DynHash {
fn dyn_hash(&self, state: &mut dyn Hasher);
}
impl<H: Hash + ?Sized> DynHash for H {
fn dyn_hash(&self, mut state: &mut dyn Hasher) {
self.hash(&mut state);
}
}
#[dyn_partial_eq]
trait HasVoice: DynHash {
fn talk(&self);
}
impl Hash for Box<dyn HasVoice> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.dyn_hash(state)
}
}
impl Eq for Box<dyn HasVoice> {}
#[derive(DynPartialEq, PartialEq, Eq, Hash, Clone)]
struct Duck {
name: String,
}
#[derive(DynPartialEq, PartialEq, Eq, Hash, Clone)]
struct Dog {
breed: String,
}
impl HasVoice for Duck {
fn talk(&self) {
println!("duck quack!")
}
}
impl HasVoice for Dog {
fn talk(&self) {
println!("dog bark!")
}
}
fn main() {
let duck: Duck = Duck {
name: "an animal".to_string(),
};
let dog: Dog = Dog {
breed: "an animal".to_string(),
};
let dog2: Dog = Dog {
breed: "an animal".to_string(),
};
let mut quack_set: HashSet<Box<dyn HasVoice>> = HashSet::new();
quack_set.insert(Box::new(duck.clone()));
quack_set.insert(Box::new(dog.clone()));
quack_set.insert(Box::new(dog2));
assert_eq!(quack_set.len(), 2);
}
So that's how you implement Java in Rust. :P
For future improvement: The problem with DynHash
If you actually test the hash function we implemented here, you will notice that it doesn't work that well. More specifically, Dog { breed: "the same string".to_string() } and Duck { name: "the same string".to_string() } hash to exactly the same value, because Hash only cares about the stored data, not the unique type. This isn't a problem in theory, but it is quite annoying, because we really should not get hash collisions between these two types that easily. There's probably a way to fix this with a proc macro, similar to dyn_partial_eq, but that's probably not worth doing here.
I am trying to implement the following trait and struct:
pub trait Funct {
fn arity(&self) -> u32;
}
#[derive(Debug, Hash, Eq, PartialEq, Clone)]
pub struct FunctionLiteral<T: Funct> {
pub function: T,
pub args: Vec< FunctionLiteral<T> >
}
pub enum Foo {
Foo
}
impl Funct for Foo {
fn arity(&self) -> u32 {0}
}
pub enum Bar {
Bar
}
impl Funct for Bar {
fn arity(&self) -> u32 {0}
}
fn main() {
let baz = FunctionLiteral{
function: Foo::Foo,
args: vec![FunctionLiteral{
function: Bar::Bar,
args: vec![]
}]
};
}
I can set it up the way I have for the generic type T to be of trait Funct, but I don't necessarily want T to be of the same type.
Here, compiling the code gives the following error:
error[E0308]: mismatched types
--> foo.rs:31:23
|
31 | function: Bar::Bar,
| ^^^^^^^^ expected enum `Foo`, found enum `Bar`
error: aborting due to previous error
Is it possible to set up FunctionLiteral such that I can have different types for function and the items of args, while forcing both of them to be of type Funct?
The problem
When you do:
Structure<T: Trait>{
inner: T,
many: Vec<T>
}
You are telling the compiler to create a specialized instance for each different T. So if you have Foo and Bar both implementing Trait, then the compiler will generate two different representations, with two different sizes:
struct Foo(u8);
impl Trait for Foo{
// impl goes here
}
struct Bar(u64);
impl Trait for Bar{
// impl goes here
}
Then the compiler will generate something like:
Structure<Foo>{
inner: Foo,
many: Vec<Foo>
}
// and
Structure<Bar>{
inner: Bar,
many: Vec<Bar>
}
Obviously you cannot put Foo instances into Bar as they are different types and have different sizes.
The solution
You need to Box<> your Funct types in order to make them the same size (i.e. pointer sized). By putting them behind a (smart) pointer you are essentially erasing their types:
let a: Box<dyn Trait> = Box::new(Foo(0));
let b: Box<dyn Trait> = Box::new(Bar(0));
Now both a and b have the same size (the size of a pointer) and have the same type - Box<dyn Trait>. So now you can do:
struct Structure{ // no longer generic!
inner: Box<dyn Trait>, // can hold any `Box<dyn Trait>`
many: Vec<Box<dyn Trait>> // can hold any `Box<dyn Trait>`
}
The downside of this approach is that it requires heap allocation and that it looses the exact type of a and b. Youno longer know if a is Foo or Bar or something else.
Instead of Box you can use any other smart pointer, such as Rc or Arc if you need its functionality.
Another option
Another option is to make Foo and Bar the same size and type. This can be done by wrapping them in an enum:
enum Holder{
Foo(Foo),
Bar(Bar), // any other types go here in their own variants
}
Then your structure will look like:
struct Structure{ // no longer generic!
inner: Holder, // can hold any Holder variant`
many: Vec<Holder> // can hold any Holder variant`
}
The downside is that you have to either implement a delegation like:
impl Trait for Holder{
fn some_method(&self){
match self{
Holder::Foo(foo) => foo.some_method(),
Holder::Bar(bar) => bar.some_method(),
}
}
}
Or match everywhere you want to use the object. Also now your Holder enum will be the size of max(sizeof(Foo), sizeof(Bar))
On the plus side:
you still know the actual type - it's not erased
no heap allocation
I have an (acyclic) tree structure using some structs. I want to codify the relations at the type-level so I can get guarantees on whether a given struct is a descendant of another.
Would it be possible to implement a macro- or blanket implementation for DescendantOf<Ancestor>? Or is there a way with associated types, even at arbitrary depth?
Struct graph
#[Derive(ParentChildRelation)]
struct GrandFather {
father: Father
}
#[Derive(ParentChildRelation)]
struct Father {
child: Child
}
#[Derive(ParentChildRelation)]
struct Child {}
Relation traits
// automatically implemented using Derive
pub trait ParentOf<Child> {}
// automatically implemented using Derive
pub trait ChildOf<Parent> where Parent: ParentOf<Self> {}
// automatically implemented using impl constraint
pub trait Descendant2<Root, Parent>
where
Root: ParentOf<Parent>,
Parent: ChildOf<Root> + ParentOf<Self>,
Self: ChildOf<Parent>
{}
pub trait Descendant3<Root, GrandFather, Parent>
where
Root: ParentOf<GrandFather>,
GrandFather: ChildOf<Root> + ParentOf<Parent>,
Parent: ChildOf<GrandFather> + ParentOf<Self>,
Self: ChildOf<Parent>
{
// and so on...
...
Blanket implementations
// blanket implement all variants 2, 3, n...
impl<Ancestor, GrandFather, Parent, T> Descendant3<Ancestor, GrandFather, Parent>
for T
where
Ancestor: ParentOf<GrandFather>,
GrandFather: ChildOf<Ancestor> + ParentOf<Parent>,
Parent: ChildOf<GrandFather> + ParentOf<T>,
T: ChildOf<Parent>
{}
// this all works
...
My goal is being able to do something like:
fn test(descendant:Obj) where Obj: DescendantOf<GrandParent>
But I don't see a way of implementing a DescendantOf<Ancestor> trait based on the more extensive DescendantX<A, B, C, ...> traits, since:
// todo: this doesnt work... how do we now get DescendantOf<Ancestor> implemented for all *X variants? this results in 'the type parameter B, C is not constrained by the impl trait, self type, or predicates' error...
impl<T: Descendant3<Ancestor, B, C>, A, B, C> DescendantOf<Ancestor> for T {}
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.
I have two structs, A and B, and I want to use a HashMap<A, B>. I have a piece of code like this:
use std::collections::HashMap;
pub struct A {
x: i32,
y: i32,
title: String,
}
pub struct B {
a: u32,
b: u32,
}
fn main() {
let map = HashMap::new();
map.insert(
A {
x: 10,
y: 20,
title: "test".to_string(),
},
B { a: 1, b: 2 },
);
}
But the compiler gives me these errors:
error[E0277]: the trait bound `A: std::cmp::Eq` is not satisfied
--> src/main.rs:16:9
|
16 | map.insert(
| ^^^^^^ the trait `std::cmp::Eq` is not implemented for `A`
error[E0277]: the trait bound `A: std::hash::Hash` is not satisfied
--> src/main.rs:16:9
|
16 | map.insert(
| ^^^^^^ the trait `std::hash::Hash` is not implemented for `A`
I know that I must implement these traits, but after hours of searching the web, I have found nothing about implementing them.
My actual code is more complicated, and my structs contain other structs (I've edited the code).
I've implemented the Hash trait:
impl std::hash::Hash for A {
fn hash<H>(&self, state: &mut H)
where
H: std::hash::Hasher,
{
state.write_i32(self.x);
state.finish();
}
}
I made an implementation for PartialEq also:
impl PartialEq for A {
fn eq(&self, other: &A) -> bool {
self.x == other.x
}
}
But the compiler continues to complain, this time about Eq:
error[E0277]: the trait bound `A: std::cmp::Eq` is not satisfied
--> src/main.rs:16:9
|
16 | map.insert(
| ^^^^^^ the trait `std::cmp::Eq` is not implemented for `A`
How can I implement Eq? Why is there no implementation in the docs?
Eq is what we call a marker trait: it has no method on its own, it is just a way for the programmer to express that the struct verifies a certain property. You can implement it like this:
impl Eq for Application {}
Or alternatively, use #[derive(Eq)] on top of the Application declaration
Eq is a trait bound by PartialEq. This means that you can implement it only on structs that also implement PartialEq (which is the case here). By implementing Eq, you make the promise that your implementation of PartialEq is reflexive (see the docs for what it means).
You can have the compiler derive these instances for you by inserting the following before your struct declaration:
#[derive(PartialEq, Eq, Hash)]
pub struct A {
// ...
}
You could also implement them manually instead. If you want to do that, you should read the documentation on traits, Eq and Hash.
This is how the Rust documentation says you write your own implementation of Hash:
use std::hash::{Hash, Hasher};
struct Person {
id: u32,
name: String,
phone: u64,
}
impl Hash for Person {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
self.phone.hash(state);
}
}
Source: https://doc.rust-lang.org/std/hash/trait.Hash.html