【问题标题】:How do I use integer number literals when using generic types?使用泛型类型时如何使用整数文字?
【发布时间】:2015-02-17 15:50:59
【问题描述】:

我想实现一个函数来计算任何通用整数类型中的位数。这是我想出的代码:

extern crate num;
use num::Integer;

fn int_length<T: Integer>(mut x: T) -> u8 {
    if x == 0 {
        return 1;
    }

    let mut length = 0u8;
    if x < 0 {
        length += 1;
        x = -x;
    }

    while x > 0 {
        x /= 10;
        length += 1;
    }

    length
}

fn main() {
    println!("{}", int_length(45));
    println!("{}", int_length(-45));
}

这是编译器的输出

error[E0308]: mismatched types
 --> src/main.rs:5:13
  |
5 |     if x == 0 {
  |             ^ expected type parameter, found integral variable
  |
  = note: expected type `T`
             found type `{integer}`

error[E0308]: mismatched types
  --> src/main.rs:10:12
   |
10 |     if x < 0 {
   |            ^ expected type parameter, found integral variable
   |
   = note: expected type `T`
              found type `{integer}`

error: cannot apply unary operator `-` to type `T`
  --> src/main.rs:12:13
   |
12 |         x = -x;
   |             ^^

error[E0308]: mismatched types
  --> src/main.rs:15:15
   |
15 |     while x > 0 {
   |               ^ expected type parameter, found integral variable
   |
   = note: expected type `T`
              found type `{integer}`

error[E0368]: binary assignment operation `/=` cannot be applied to type `T`
  --> src/main.rs:16:9
   |
16 |         x /= 10;
   |         ^ cannot use `/=` on type `T`

我知道问题来自我在函数中使用常量,但我不明白为什么 Integer 的特征规范不能解决这个问题。

The documentation for Integer 表示它使用Self 实现了PartialOrd 等特征(我假设它指的是Integer)。通过使用也实现 Integer 特征的整数常量,操作是否已定义,编译器不应该无错误地编译吗?

我尝试使用i32 为我的常量添加后缀,但错误消息相同,将_ 替换为i32

【问题讨论】:

    标签: generics int rust traits


    【解决方案1】:

    这里有很多问题:

    1. As Shepmaster says01 无法转换为实现 Integer 的所有内容。请改用Zero::zeroOne::one
    2. 10 绝对不能转换为实现Integer 的任何东西,你需要使用NumCast 来实现
    3. a /= b 不是 a = a / b 的糖,而是 Integer 不需要的单独特征。
    4. -x 是一元运算,它不属于 Integer,但需要 Neg 特征(因为它只对有符号类型有意义)。

    这是一个实现。请注意,您需要对Neg 进行绑定,以确保它产生与T 相同的类型

    extern crate num;
    
    use num::{Integer, NumCast};
    use std::ops::Neg;
    
    fn int_length<T>(mut x: T) -> u8
    where
        T: Integer + Neg<Output = T> + NumCast,
    {
        if x == T::zero() {
            return 1;
        }
    
        let mut length = 0;
        if x < T::zero() {
            length += 1;
            x = -x;
        }
    
        while x > T::zero() {
            x = x / NumCast::from(10).unwrap();
            length += 1;
        }
    
        length
    }
    
    fn main() {
        println!("{}", int_length(45));
        println!("{}", int_length(-45));
    }
    

    【讨论】:

    • 非常感谢您指出所有这些!我想我最好用SignedInt 替换Int + Neg &lt;...&gt;
    • 因此,如果您的功能稍作更改,则可以使用任何数字 \o/ 非常感谢!
    • SignedInt 有一个问题,您将无法使用无符号值;)请参阅 playpen:is.gd/YPhjla
    • @ker 我认为 unsigned int 没有实现 Neg 特征......但我显然没有充分了解它!谢谢 !我肯定有一些阅读等着我......
    • 只需将#[inline(never)] 添加到您的ten 函数中,打开发布模式并生成llvm 代码。然后你可以看到,i32 的单态泛型函数被优化为单个 ret i32 10 语句
    【解决方案2】:

    问题在于Integer trait 可以由anything 实现。例如,您可以选择在自己的结构上实现它!没有办法将文字 01 转换为您的结构。我懒得展示一个实现它的例子,因为有 10 种左右的方法。 ^_^

    num::Zeronum::One

    这就是Zero::zeroOne::one 存在的原因。您可以(非常烦人)通过重复调用这些常量来创建所有其他常量。

    use num::{One, Zero}; // 0.4.0
    
    fn three<T>() -> T
    where
        T: Zero + One,
    {
        let mut three = Zero::zero();
        for _ in 0..3 {
            three = three + One::one();
        }
        three
    }
    

    FromInto

    您还可以使用 FromInto 特征转换为您的泛型类型:

    use num::Integer; // 0.4.0
    use std::ops::{DivAssign, Neg};
    
    fn int_length<T>(mut x: T) -> u8
    where
        T: Integer + Neg<Output = T> + DivAssign,
        u8: Into<T>,
    {
        let zero = 0.into();
        if x == zero {
            return 1;
        }
    
        let mut length = 0u8;
        if x < zero {
            length += 1;
            x = -x;
        }
    
        while x > zero {
            x /= 10.into();
            length += 1;
        }
    
        length
    }
    
    fn main() {
        println!("{}", int_length(45));
        println!("{}", int_length(-45));
    }
    

    另见:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 1970-01-01
      • 2021-09-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多