预期类型参数T
,发现类型参数A
错误显示。我也编写了生命周期实现代码,但它仍然不能解决问题。我做错了什么?
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
// }
// }
最佳答案
T
和A
不必是同一类型,所以你有两个问题。
第一个是你约束 T
和A
成为PartialOrd
,与 PartialOrd<Self>
相同。所以你的实际约束是 T: PartialOrd<T>, A: PartialOrd<A>
。这意味着您可以比较 T
的顺序发送至其他 T
的和A
发送至其他 A
的,但是x > y
比较 T
到A
.
相反,您需要约束 T: PartialOrd<A>
。 (这也失败了,但是因为main()
中的调用——稍后会详细介绍。)
其次,该函数声明返回 T
但是else
区 block 返回y
,这不是 T
。 Rust 是静态类型的,因此它期望类型完全匹配。
可以通过要求 A
来解决此问题可以转换为T
(即 A: Into<T>
)然后您可以返回 y.into()
来自else
block 。
所以此时,我们有:
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()
}
}
但现在你还有更多问题:
- 没有类型
T
和A
满意T: PartialOrd<A>
哪里T
是一个整数且A
是一个 float ,因此您不能使用3
调用此函数和5.0
就像你在main()
中所做的那样. - 同样,
Into<T>
也没有实现上A
对于整数类型T
和浮点类型A
. -
x > y
将移动x
和y
,之后您将无法归还它们。通过限制T
可以轻松解决这个问题。和A
成为Copy
.
第二个问题可以通过使用一个表示“T
或A
”的枚举并返回它来解决。 either
crate has such a type called Either
,我们可以在这里使用 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)
}
}
(println!
之所以有效,是因为当 Either<T, A>
和 Display
都实现时,T
实现了 A
。)
您仍然面临整数和 float 之间没有内置排序实现的问题。
“万岁玛丽”解决方案可能是要求 T
和A
都可以转换为f64
然后转换x
和y
至f64
在比较它们之前:
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)
}
}
这是我们实际编译的第一段代码,这可能足以满足您的目的。然而,仍然存在一些问题:
-
i64
和u64
无法无损转换为f64
,因此他们不实现Into<f64>
,所以如果你改变let x = 3;
至let x = 3u64;
(或3i64
)编译将再次失败。 -
f64
不实现Ord
因为可能有两个f64
值x
和y
不相等,但都不大于另一个——如果任一值为NaN
, 例如。这不会导致您的程序崩溃,但可能会产生意外或不正确的结果。
我怀疑这是一个学习练习,所以希望这个答案可以帮助您理解原始代码有什么问题。我不会推荐在现实世界的程序中使用这样的函数;相反,最好将两个参数转换为相同的 Ord
-提前实现类型,然后你可以使用内置的 std::cmp::max
函数(或 Ord::max
)。
关于rust - Rust 泛型上的类型参数不匹配错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75038278/