Suppose I have the following structs
:
struct Oranges { i: i32 }
struct Apples { i: i32 }
struct Chairs { i: i32 }
I can define a set of Apples
and Oranges
and count them up as a bunch of fruits.
let o = Oranges{i: 4};
let a = Apples{i: 3};
let fruits = o.i + a.i;
println!("I have {} fruits", fruits) // I have 7 fruits.
If I write a function I can do this dynamically, but this is restrictive becuase argument 1 must be Apples
and argument 2 must be Oranges
.
fn count(a: &Apples, o: &Oranges) -> i32 {
a.i + o.i
}
println!("I have {} fruits", count(&a, &o)); // I have 7 fruits.
count
function that accepts either Apples
or Oranges
as types?I realise that this must seem quite trivial to one experienced in Rust. I have introduced Chairs
as a comparator that is not allowed.
I have tried to implement traits
with compiler errors:
trait Fruit {}
impl Fruit for Apples {}
impl Fruit for Oranges {}
fn count<T, S>(a: &T, o: &S) -> i32
where T: Fruit, S: Fruit
{
a.i + o.i
} ^ unknown field error[E0609]
I have also tried to use enums
but that just seems to create such a combinatorial mess that I assume there is a much better way.
enum Fruit{
O(Oranges),
A(Apples)
}
fn count(a: &Fruit, b: &Fruit) -> i32
{
match (a, b) {
(Fruit::O(x), Fruit::O(y)) => x.i + y.i,
(Fruit::O(x), Fruit::A(y)) => x.i + y.i,
(Fruit::A(x), Fruit::O(y)) => x.i + y.i,
(Fruit::A(x), Fruit::A(y)) => x.i + y.i,
}
}
println!("I have {} fruits", count(&Fruit::A(a), &Fruit::O(o))); // I have 7 fruits.
Two possibilities:
count
methodTraits can't declare or access fields, so you need to have a count
method that you implement for each type of fruit that returns the correct value:
trait Fruit {
fn count (&self) -> i32;
}
impl Fruit for Apples {
fn count (&self) -> i32 { self.i }
}
impl Fruit for Oranges {
fn count (&self) -> i32 { self.i }
}
fn count<T, S>(a: &T, o: &S) -> i32
where T: Fruit, S: Fruit
{
a.count() + o.count()
}
enum
with a count
method to avoid the combinatorial messenum Fruit{
O(Oranges),
A(Apples)
}
impl Fruit {
fn count (&self) -> i32 {
match self {
Fruit::O (o) => o.i,
Fruit::A (a) => a.i,
}
}
}
fn count(a: &Fruit, b: &Fruit) -> i32
{
a.count() + b.count()
}
If you have a lot of fruit types, you can avoid repeated code for either solution with macros, e.g.:
trait Fruit {
fn count (&self) -> i32;
}
macro_rules! impl_fruit {
($($f:ident),*) => {
$(
impl Fruit for $f {
fn count (&self) -> i32 { self.i }
}
)*
}
}
impl_fruit!(Apples, Oranges);
fn count<T, S>(a: &T, o: &S) -> i32
where T: Fruit, S: Fruit
{
a.count() + o.count()
}