将整数拆分为单个数字

Ele*_*fee 8 digits rust

我正在编写一个函数,它需要一个更大整数的个别数字来执行操作.

我尝试过以下方法:

// I can safely unwrap because I know the chars of the string are going to be valid
let digits = num.to_string().chars().map(|d| d.to_digit(10).unwrap());
Run Code Online (Sandbox Code Playgroud)

但借阅检查员表示字符串的寿命不够长.

以下工作:

let temp = num.to_string();
let digits = temp.chars().map(|d| d.to_digit(10).unwrap());
Run Code Online (Sandbox Code Playgroud)

但这看起来更加做作.

这样做有更好的,可能更自然的方式吗?

She*_*ter 8

但借阅检查员表示字符串的寿命不够长.

那是因为它没有.你没有使用迭代器,所以类型digits

std::iter::Map<std::str::Chars<'_>, <closure>>
Run Code Online (Sandbox Code Playgroud)

也就是说,还没有到被评估的迭代器,包含对分配的字符串(未命名的寿命引用'_Chars).但是,由于该字符串没有所有者,因此在语句结束时删除它.在迭代器被消耗之前.

所以,对于Rust来说,它阻止了一个免费使用后的bug!

使用迭代器会"解决"问题,因为对分配的字符串的引用不会尝试比分配的字符串活得更久; 他们都在声明的最后结束:

let digits: Vec<_> = num.to_string().chars().map(|d| d.to_digit(10).unwrap()).collect();
Run Code Online (Sandbox Code Playgroud)

至于另一种解决方案,那就是从C++问题中窃取数学方法:

fn x(n: usize) -> Vec<usize> {
    fn x_inner(n: usize, xs: &mut Vec<usize>) {
        if n >= 10 {
            x_inner(n / 10, xs);
        }
        xs.push(n % 10);
    }
    let mut xs = Vec::new();
    x_inner(n, &mut xs);
    xs
}

fn main() {
    let num = 42;
    let digits: Vec<_> = num.to_string().chars().map(|d| d.to_digit(10).unwrap()).collect();
    println!("{:?}", digits);
    let digits = x(42);
    println!("{:?}", digits);
}
Run Code Online (Sandbox Code Playgroud)

但是,您可能希望为负数添加所有特殊情况逻辑,并且测试不是一个坏主意.

您可能还需要一个花式裤子迭代器版本:

struct Digits {
    n: usize,
    divisor: usize,
}

impl Digits {
    fn new(n: usize) -> Self {
        let mut divisor = 1;
        while n >= divisor * 10 {
            divisor *= 10;
        }

        Digits {
            n: n,
            divisor: divisor,
        }
    }
}

impl Iterator for Digits {
    type Item = usize;

    fn next(&mut self) -> Option<Self::Item> {
        if self.divisor == 0 {
            None
        } else {
            let v = Some(self.n / self.divisor);
            self.n %= self.divisor;
            self.divisor /= 10;
            v
        }

    }
}

fn main() {
    let digits: Vec<_> = Digits::new(42).collect();
    println!("{:?}", digits);
}
Run Code Online (Sandbox Code Playgroud)

  • @ElectricCoffee:free-after-free之所以出现,是因为`to_string`创建了一个临时版,它只与它创建它的语句一样长.然而,你的`digits`迭代器,通过引用这个临时工作,生活得更长,这是不正确的.如果你在同一个语句中立即调用`collect`,则不再存在问题. (3认同)

归档时间:

查看次数:

2982 次

最近记录:

9 年 前