use*_*366 2 generics traits rust
我在 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));
}
Run Code Online (Sandbox Code Playgroud)
问题似乎是按位与结果与 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
Run Code Online (Sandbox Code Playgroud)
顺便说一句,我只是在玩弄特征和泛型,这并不是测试整数是否为奇数的最佳方法。
你的代码无法工作的主要原因是 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()
}
Run Code Online (Sandbox Code Playgroud)
(我删除了无用的语法部分)
当然,如果你应用它,你会发现更多问题:
BitAnd不保证其输出以任何方式与其输入相关,因此您需要将其限制为有意义的内容,一种选择是仅要求T & T返回T:
fn is_odd<T: BitAnd<Output=T> + Eq + One>(x: &T) -> bool {
*x & T::one() == T::one()
}
Run Code Online (Sandbox Code Playgroud)
您无法将内容从引用中移出,这正是*x此处尝试做的。您可以限制x类型Copy(允许复制引用),或者只是不进行x引用,我选择了后者,因为我没有看到这一点:
fn is_odd<T: BitAnd<Output=T> + Eq + One>(x: T) -> bool {
x & T::one() == T::one()
}
Run Code Online (Sandbox Code Playgroud)
就这样,如果您修复调用站点以删除引用,它现在就可以工作了。is_odd现在可以像您想要的那样灵活地工作(如果一个类型碰巧以一种没有意义的方式实现所有三个操作,这可能是完全不连贯的,这可能就是为什么num具有is_oddInteger 特征的非默认操作)。
顺便说一句,在这种情况下,您的 println 是过于复杂的版本dbg:
fn is_odd<T: BitAnd<Output=T> + Eq + One>(x: &T) -> bool {
*x & T::one() == T::one()
}
Run Code Online (Sandbox Code Playgroud)
=>
[src/main.rs:9] is_odd(23_u64) = true
Run Code Online (Sandbox Code Playgroud)
另外,您也可以摆脱转换版本(不使用num),但在这种情况下,正如最初所述,您需要准确地告诉编译器您需要什么转换,这里特别T需要从 u8 进行转换,又名T: From<u8>。此替代版本也适用于这种情况
fn is_odd<T: BitAnd<Output=T> + Eq + One>(x: T) -> bool {
x & T::one() == T::one()
}
Run Code Online (Sandbox Code Playgroud)
但如果您尝试运行它T: i8(例如,您可以将 u8 转换为 i16,但不能转换为 i8,因为一半范围无效),则不会。
您可以TryFrom通过类似的设置来用于此特定的极端情况T: TryFrom<u8>。然后使用ok().unwrap(), 或者只是1.try_into().unwrap()限制错误:
dbg!(is_odd(23_u64));
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
58 次 |
| 最近记录: |