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

Léo*_*lli 7 generics int traits rust

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

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));
}
Run Code Online (Sandbox Code Playgroud)

这是编译器输出

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`
Run Code Online (Sandbox Code Playgroud)

我明白问题来自于我在函数中使用常量,但我不明白为什么特征规范Integer没有解决这个问题.

它的文档Integer说它实现了PartialOrd等特征Self(我假设参考Integer).通过使用也实现Integer特征的整数常量,不是定义的操作,编译器不应该编译没有错误?

我尝试用我的常量后缀i32,但错误信息是相同的,替换_i32.

oli*_*obk 9

这里有很多问题:

  1. 正如Shepmaster所说,0并且1无法转换为实现的一切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));
}
Run Code Online (Sandbox Code Playgroud)


She*_*ter 8

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

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
}
Run Code Online (Sandbox Code Playgroud)

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));
}
Run Code Online (Sandbox Code Playgroud)

也可以看看: