【问题标题】:Is it possible to write a generic integer length function in Rust?是否可以在 Rust 中编写通用整数长度函数?
【发布时间】:2020-03-22 04:25:50
【问题描述】:

我为u32 写了一个长度函数。我可以轻松地复制/粘贴/编辑到其他 int 类型,但是当我尝试使用泛型时,我遇到了困难。有没有我误解的概念?

传递长度函数

fn len_int(n: u32) -> u32 { // 0
    std::iter::repeat_with({
        let mut l = 0;
        // can't call pow on ambiguous numeric type
        move || match n / 10u32.pow(l) { // 1
            0 => 0,
            _ => {
                l += 1;
                1
            }
        }
    })
        .take_while(|&x| x != 0)
        // count returns usize
        .count() as u32 // 2
}

一个失败的通用长度函数:I

fn len_int<T>(n: T) -> T
where
    T: Copy + Clone,
{
    std::iter::repeat_with({
        let mut l = 0;
        move || match n / 10.pow(l) {
            //1
            0 => 0,
            _ => {
                l += 1;
                1
            }
        }
    })
    .take_while(|&x| x != 0)
    .count() at T // 2
}

编译器告诉我不能 call method pow on ambiguous numeric type {integer} cannot divide T by type error 或者在末尾用as T 转换count(),因为T 不是原始类型。 playground

【问题讨论】:

  • 它是如何/在哪里失败的?包括错误消息和详细信息。
  • 提供的游乐场链接导致完全不同的代码......
  • @jmb,对不起,这似乎有时会发生,忘记检查它。现在可以了。
  • 请参阅stackoverflow.com/questions/26810793/… 以了解如何处理通用整数类型。此外,一些指数数学告诉我,无论你传入什么整数,你永远不会溢出usize,这就是.count() 返回的内容。因此,你真的应该只返回usize
  • 另外,计算一个数字在给定基数(在本例中为 10)中所占位数的最简单方法是计算该数字在所述基数中的对数。在这种情况下,记录以 x 为底的十。然后,取其上限使其成为一个整数。示例:play.rust-lang.org/…

标签: generics rust


【解决方案1】:

您的脑海中可能有特定的类型,但编译器不知道这一点。对于编译器来说,泛型类型T 可以是任何东西。它可以是一个字符串。它可以是对函数指针的引用。它可以是文件句柄的向量。 任何东西。因此,它将要求您的代码同时处理所有这些可能的类型。

要使用更具体的类型,您必须提前声明您希望该类型支持的所有内容。编译器不会让你使用任何你没有声明的操作。

Rust 的标准库中没有 .pow 的特征,因此您不能开箱即用地声明它。您可以自己制作,也可以使用num-traits

【讨论】:

    【解决方案2】:

    我们可以定义一个特征,然后为您希望在泛型函数中支持的具体类型实现该特征:

    pub trait IntLenExt<T> {
        fn is_divis(&self, power: u32) -> bool;
        fn cast_count(count: usize) -> T;
    }
    
    impl IntLenExt<u32> for u32 {
        fn is_divis(&self, power: u32) -> bool {
            self / 10u32.pow(power) == 0
        }
    
        fn cast_count(count: usize) -> u32 {
            count as u32
        }
    }
    
    impl IntLenExt<u64> for u64 {
        fn is_divis(&self, power: u32) -> bool {
            self / 10u64.pow(power) == 0
        }
    
        fn cast_count(count: usize) -> u64 {
            count as u64
        }
    }
    
    fn len_int<T>(n: T) -> T
    where
        T: Copy + Clone + IntLenExt<T>,
    {
        T::cast_count(std::iter::repeat_with({
            let mut l = 0;
            move || match n.is_divis(l) {
                //1
                true => 0,
                false => {
                    l += 1;
                    1
                }
            }
        })
        .take_while(|&x| x != 0)
        .count()) // 2
    }
    
    
    fn main() {
        let input: u64 = 100;
        println!("len_int({}) => {}", input, len_int(input));
    }
    

    【讨论】:

      猜你喜欢
      • 2020-03-23
      • 2021-03-21
      • 1970-01-01
      • 1970-01-01
      • 2010-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多