我在 C++ 方面有经验,并开始尝试 Rust。
尝试实现一些简单的通用函数,我遇到了以下问题:
use std::ops::BitAnd;
use std::cmp::Eq;
fn is_odd_i32(x: u32) -> bool {
if x & 1_u32 == 1_u32 { true } else { false }
}
fn is_odd<T: BitAnd + Eq>(x: &T) -> bool {
if (*x & (1 as T)) == (1 as T) { true } else { false }
}
fn main() {
println!("is_odd -> '{}'", is_odd(&23_u64));
println!("is_odd -> '{}'", is_odd(&23_u32));
}
问题似乎是按位与结果与 0 或 1 的比较。我知道要使其工作,1(或 0)必须可转换为类型 T,但不知道如何实现这一点。我也尝试过
T::try_from(1_u8).ok().unwrap()
但这也不起作用。
我不明白如何解决这个问题...
我得到的错误是:
error[E0369]: binary operation `==` cannot be applied to type `<T as BitAnd>::Output`
--> src/main.rs:27:24
|
27 | if (*x & (1 as T)) == (1 as T) { true } else { false }
| --------------- ^^ -------- T
| |
| <T as BitAnd>::Output
|
help: consider further restricting the associated type
|
26 | fn is_odd<T: BitAnd + Eq>(x: &T) -> bool where <T as BitAnd>::Output: PartialEq<T> {
| +++++++++++++++++++++++++++++++++++++++++
error[E0605]: non-primitive cast: `{integer}` as `T`
--> src/main.rs:27:14
|
27 | if (*x & (1 as T)) == (1 as T) { true } else { false }
| ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error[E0605]: non-primitive cast: `{integer}` as `T`
--> src/main.rs:27:27
|
27 | if (*x & (1 as T)) == (1 as T) { true } else { false }
| ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
顺便说一句,我只是在玩弄特征和泛型,这不是测试整数是否为奇数的最佳方法。
你的代码无法工作的第一个原因是 Rust 的泛型与 C++ 的模板的工作原理完全不同。
在 Rust 的泛型中,约束是你唯一可以依赖的东西。所以当你写下
T: BitAnd + Eq
时,这就是 T
的能力范围。这里没有任何内容表明 T
甚至是一个数字,据您所知,为了方便起见,有人在哈希集上实现了 &
。因此,你的强制转换对编译器来说绝对没有意义,因此它会抱怨。
要为此使用泛型,您需要一种通用的方式来表达这些操作,类似于“数字塔”,它将所有基本数字操作定义为泛型,但早在早期,核心团队就认为这不是一个努力这对于核心语言和标准库很有用,而过去仅有的少量内容已被删除/移至num 生态系统。为此,特别是
One
特质:
fn is_odd<T: BitAnd + Eq + One>(x: &T) -> bool {
*x & T::one() == T::one()
}
(我删除了无用的语法部分)
当然,如果你应用它,你会发现更多问题:
BitAnd
不保证其输出以任何方式与其输入相关,因此您需要将其限制为有意义的内容,一种选择是仅要求 T & T
返回 T
:
fn is_odd<T: BitAnd<Output=T> + Eq + One>(x: &T) -> bool {
*x & T::one() == T::one()
}
您无法将内容从引用中移出,这正是
*x
在这里尝试做的事情。您可以将 x
限制为 Copy
类型(允许复制引用),或者只是不将 x
用作引用,我选择了后者,因为我看不到要点:
fn is_odd<T: BitAnd<Output=T> + Eq + One>(x: T) -> bool {
x & T::one() == T::one()
}
就这样,如果您修复调用站点以删除引用,它现在就可以工作了。