I would like to write an add
function that can take as input either i64
or f64
for the two parameters.
I was able to come up with the following:
use std::ops::Add;
fn add<T: Add<Output = T>>(a: T, b: T) -> T{
a + b
}
fn main() {
let a: i64 = 10;
let b: i64 = 20;
let c: f64 = 10.5;
let d: f64 = 20.5;
println!("{:?}", add(a, b)); // Outputs: 30
println!("{:?}", add(c, d)); // Outputs: 31.0
}
Is it possible to modify this function so that it's possible to have :
i64
f64
If either of the parameters is an f64
we do a cast, and return an f64
.
type of a |
type of b |
returned type |
---|---|---|
i64 |
i64 |
i64 |
i64 |
f64 |
f64 |
f64 |
i64 |
f64 |
f64 |
f64 |
f64 |
The main function would have the following output:
fn main() {
let a: i64 = 10;
let b: i64 = 20;
let c: f64 = 10.5;
let d: f64 = 20.5;
println!("{:?}", add(a, b)); // Outputs: 30 | i64 + i64 -> i64
println!("{:?}", add(a, c)); // Outputs: 20.5 | i64 + f64 -> f64
println!("{:?}", add(c, a)); // Outputs: 20.5 | f64 + i64 -> f64
println!("{:?}", add(c, d)); // Outputs: 30.0 | f64 + f64 -> f64
}
You can do this using a trait. The trait can be identical to the built-in Add
trait, but due to the orphan rule you can't use the Add
trait itself. Here's an example implementation:
pub trait MyAdd<RHS> {
type Output;
fn add(self, b: RHS) -> Self::Output;
}
impl MyAdd<i64> for i64 {
type Output = i64;
fn add(self, b: i64) -> Self::Output {
self + b
}
}
impl MyAdd<f64> for f64 {
type Output = f64;
fn add(self, b: f64) -> Self::Output {
self + b
}
}
impl MyAdd<i64> for f64 {
type Output = f64;
fn add(self, b: i64) -> Self::Output {
self + b as f64
}
}
impl MyAdd<f64> for i64 {
type Output = f64;
fn add(self, b: f64) -> Self::Output {
self as f64 + b
}
}
pub fn add<T, U>(a: T, b: U) -> T::Output
where
T: MyAdd<U>,
{
a.add(b)
}
The orphan rule prevents you from implementing foreign traits on foreign types. The code above works around that by using a custom trait. Alternatively, you could use custom types, i.e. newtype wrappers around i64
and f64
. Since the implementation matches the built-in implementation of addition, it would be enough to wrap one of the two types in a newtype wrapper.