使用泛型类型时如何使用整数文字?

How do I use integer number literals when using generic types?

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

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 说它实现了 PartialOrd 等特征 Self(我假设指的是 Integer)。通过使用也实现了 Integer 特性的整数常量,是否定义了操作,编译器不应该编译无误?

我尝试用 i32 作为常量后缀,但错误消息是一样的,将 _ 替换为 i32

问题是 Integer 特征可以通过 任何东西 实现。例如,您可以选择在自己的结构上实现它!没有办法将文字 01 转换为您的结构。我懒得展示一个实现它的例子,因为有 10 种左右的方法。 ^_^

num::Zeronum::One

这就是 Zero::zero and One::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));
}

另请参阅:

这里有很多问题:

  1. 01 无法转换为实现 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));
}