Разбиение целого числа на отдельные цифры


Я пишу функцию, которая требует, чтобы отдельные цифры большего целого числа выполняли операции.

Я попробовал следующее:

// 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());
Но проверка заимствования говорит, что строка живет недостаточно долго.

Работает следующее:

let temp = num.to_string();
let digits = temp.chars().map(|d| d.to_digit(10).unwrap());
Но это почему-то выглядит еще более надуманным. Есть ли лучший и, возможно, более естественный способ сделать это?
1 3

1 ответ:

Но проверка заимствования говорит, что строка живет недостаточно долго.

Это потому, что он не. Вы не используете итератор, поэтому Тип digits -

std::iter::Map<std::str::Chars<'_>, <closure>>

То есть еще не оцененный итератор, содержащий ссылки на выделенную строку (Безымянное время жизни '_ в Chars). Однако, поскольку у этой строки нет владельца,она отбрасывается в конце инструкции; перед использованием итератора.

Итак, ура для ржавчины, это предотвратило используйте-после-свободного бага!

Использование итератора "решит" проблему, так как ссылки на выделенную строку не будут пытаться жить дольше, чем выделенная строка; все они заканчиваются в конце утверждения:

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

Что касается альтернативного решения, есть математический способ , украденный из вопроса 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);
}
Тем не менее, вы можете добавить всю логику особых случаев для отрицательных чисел, и тестирование не будет плохой идеей.

Вы могли бы также нужна версия итератора fancy-pants:

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);
}