Reputation: 129
expected type parameter T
, found type parameter A
error display. I have written lifetime implementation code also but it stills doesn't solve the problem. What's wrong I am doing?
fn main() {
let x = 3;
let y = 5.0;
let max_value = max(x, y);
println!("The maximum value is {}", max_value);
}
fn max<T: PartialOrd, A: PartialOrd>(x: T, y: A) -> T {
if x > y {
x
} else {
y
}
}
// fn main() {
// let x = 3;
// let y = 5.0;
// let max_value = max(&x, &y);
// println!("The maximum value is {}", max_value);
// }
// fn max<'a, T: PartialOrd + Copy, A: PartialOrd + Copy>(x: &'a T, y: &'a A) -> &'a T {
// if x > y {
// x
// } else {
// y
// }
// }
Upvotes: 2
Views: 223
Reputation: 169008
T
and A
do not have to be the same type, so you have two problems.
The first is that you constrain T
and A
to be PartialOrd
, which is the same thing as PartialOrd<Self>
. So your actual constraints are T: PartialOrd<T>, A: PartialOrd<A>
. This means you can compare the order of T
's to other T
's and A
's to other A
's, but x > y
compares a T
to an A
.
Instead, you need to constrain T: PartialOrd<A>
. (This also fails, but because of the invocation in main()
-- more on that later.)
Second, the function is declared to return T
but the else
block returns y
, which is not a T
. Rust is statically typed, so it expects the types to exactly match.
This could be fixed by requiring that A
can be converted to T
(that is, A: Into<T>
) and then you can return y.into()
from the else
block.
So at this point, we have:
fn main() {
let x = 3;
let y = 5.0;
let max_value = max(x, y);
println!("The maximum value is {}", max_value);
}
fn max<T: PartialOrd<A>, A: Into<T>>(x: T, y: A) -> T {
if x > y {
x
} else {
y.into()
}
}
But now you are left with more problems:
T
and A
satisfying T: PartialOrd<A>
where T
is an integer and A
is a float, therefore you cannot call this function with 3
and 5.0
as you do in main()
.Into<T>
on A
for an integer type T
and a float type A
.x > y
will move x
and y
, and then you cannot return them later. This is trivially fixed by constraining both T
and A
to be Copy
.The second issue could be fixed by having an enum that means "either T
or A
" and returning that instead. The either
crate has such a type called Either
, which we can use here as Either<T, A>
:
use either::Either;
fn main() {
let x = 3;
let y = 5.0;
let max_value = max(x, y);
println!("The maximum value is {}", max_value);
}
fn max<T: PartialOrd<A> + Copy, A: Copy>(x: T, y: A) -> Either<T, A> {
if x > y {
Either::Left(x)
} else {
Either::Right(y)
}
}
(The println!
works because Either<T, A>
implements Display
when both T
and A
do.)
You are still left with the problem where there's no built-in ordering implementation between integers and floats.
A "hail mary" solution could be to require that T
and A
can both be converted to f64
and then convert x
and y
to f64
before comparing them:
use either::Either;
fn main() {
let x = 3;
let y = 5.0;
let max_value = max(x, y);
println!("The maximum value is {}", max_value);
}
fn max<T: Copy + Into<f64>, A: Copy + Into<f64>>(x: T, y: A) -> Either<T, A> {
if x.into() > y.into() {
Either::Left(x)
} else {
Either::Right(y)
}
}
This is the first bit of code we have that actually compiles, and this might be good enough for your purposes. There are still some issues that remain, however:
i64
and u64
cannot be losslessy converted to f64
, therefore they do not implement Into<f64>
, and so if you change let x = 3;
to let x = 3u64;
(or 3i64
) compilation will again fail.f64
does not implement Ord
because it's possible for there to be two f64
values x
and y
that are not equal but neither is greater than the other -- if either value is NaN
, for example. This won't cause your program to crash, but it may produce an unexpected or incorrect result.I suspect that this is a learning exercise, so hopefully this answer helps you understand what is wrong with the original code. I would not recommend a function like this in a real-world program; instead, it would be far better to convert both arguments to be of the same Ord
-implementing type ahead of time and then you can use the built-in std::cmp::max
function (or Ord::max
).
Upvotes: 4