无法实现整数类型的通用 fn

问题描述 投票:0回答:1

我在 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

顺便说一句,我只是在玩弄特征和泛型,这不是测试整数是否为奇数的最佳方法。

generics rust traits
1个回答
1
投票

你的代码无法工作的第一个原因是 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()
    }
    

就这样,如果您修复调用站点以删除引用,它现在就可以工作了。

© www.soinside.com 2019 - 2024. All rights reserved.