Reputation: 1162
Rust beginner here. I have this "binary calculator" that uses a couple of types..
pub enum Bit { Off, On };
pub struct Binary([Bit; 64]);
Ignoring everything else that is implemented for them, I overloaded the operators for the Binary
like so...
impl Add for Binary {
type Output = Binary;
/// Basic implementation of full addition circuit
fn add(self, other: Binary) -> Binary {
...
}
}
... Div, Sub, and Mul
... where each operator consumes the Binary
s passed to them. I was then able to define a set of public functions that took care of converting, calling, and printing everything how I wanted to...
pub fn add(x: i64, y: i64) -> Calc {
execute(Binary::add, x, y)
}
pub fn subtract(x: i64, y: i64) -> Calc {
execute(Binary::sub, x, y)
}
...
fn execute(f: fn(Binary, Binary) -> Binary, x: i64, y: i64) -> Calc {
let bx = Binary::from_int(x);
println!("{:?}\n{}\n", bx, x);
let by = Binary::from_int(y);
println!("{:?}\n{}\n", by, y);
let result = f(bx, by);
println!("{:?}", result);
result.to_int()
}
This worked, but the operations consumed the Binary
s, which I didn't actually want. So instead, I implemented the traits using references instead...
impl<'a, 'b> Add<&'b Binary> for &'a Binary {
type Output = Binary;
/// Basic implementation of full addition circuit
fn add(self, other: &'b Binary) -> Binary {
...
}
}
Now, though, I cannot figure out how to pass those functions to execute
as I did before. For example, execute(Binary::div, x, y)
is giving the following error.
error[E0277]: cannot divide `types::binary::Binary` by `_`
--> src/lib.rs:20:13
|
20 | execute(Binary::div, x, y)
| ^^^^^^^^^^^ no implementation for `types::binary::Binary / _`
|
= help: the trait `std::ops::Div<_>` is not implemented for
`types::binary::Binary`
How can I pass that specific implementation with lifetimes? I assume that I need to update the signature for execute
too, like...
fn execute<'a, 'b>(f: fn(&'a Binary, &'b Binary) -> Binary, ...
But I wind up also seeing...
error[E0308]: mismatched types
--> src/lib.rs:20:13
|
20 | execute(Binary::div, x, y)
| ^^^^^^^^^^^ expected reference, found struct `types::binary::Binary`
|
= note: expected type `fn(&types::binary::Binary, &types::binary::Binary) -> types::binary::Binary`
found type `fn(types::binary::Binary, _) -> <types::binary::Binary as std::ops::Div<_>>::Output {<types::binary::Binary as std::ops::Div<_>>::div}`
Being a complete beginner, I was able to follow all the error messages that got me to the "working" point (where operations consumed the values), but now I'm a bit out of my league, I think.
Upvotes: 0
Views: 91
Reputation: 36071
I made an exemplary implementation for addition (I made some assumptions regarding the return type of execute
and others, you'd have to adapt this if my assumptions are wrong):
use std::ops::Add;
#[derive(Debug)]
pub enum Bit { Off, On }
#[derive(Debug)]
pub struct Binary([Bit; 32]);
impl Binary {
fn to_int(&self) -> i64 {unimplemented!()}
fn from_int(n: i64) -> Self {unimplemented!()}
}
impl<'a, 'b> Add<&'b Binary> for &'a Binary {
type Output = Binary;
fn add(self, other: &'b Binary) -> Binary {
unimplemented!()
}
}
pub fn add(x: i64, y: i64) -> i64 {
execute(|a, b| a+b, x, y)
}
fn execute(f: fn(&Binary, &Binary) -> Binary, x: i64, y: i64) -> i64 {
let bx = Binary::from_int(x);
println!("{:?}\n{}\n", bx, x);
let by = Binary::from_int(y);
println!("{:?}\n{}\n", by, y);
let result = f(&bx, &by);
println!("{:?}", result);
result.to_int()
}
Note that within execute
, you'd have to call f(&bx, &by)
(i.e. borrow them instead of consuming).
However: I wondered why you chose to have fn(&Binary, &Binary) -> Binary
as argument type instead of making execute
generic over F
, constraining F
to be a callable:
fn execute<F>(f: F, x: i64, y: i64) -> i64
where
F: Fn(&Binary, &Binary) -> Binary,
{
let bx = Binary::from_int(x);
println!("{:?}\n{}\n", bx, x);
let by = Binary::from_int(y);
println!("{:?}\n{}\n", by, y);
let result = f(&bx, &by);
println!("{:?}", result);
result.to_int()
}
This way, you are a bit more flexible (you can e.g. pass closures capturing variables in their scope).
Upvotes: 1