But the borrow checker says the string doesn't live long enough.
That's because it doesn't. You aren't using the iterator, so the type of digits
is
std::iter::Map<std::str::Chars<'_>, <closure>>
That is, a yet-to-be-evaluated iterator that contains references to the allocated string (the unnamed lifetime '_
in Chars
). However, since that string has no owner, it is dropped at the end of the statement; before the iterator is consumed.
So, yay for Rust, it prevented a use-after-free bug!
Consuming the iterator would "solve" the problem, as the references to the allocated string would not attempt to live longer than the allocated string; they all end at the end of the statement:
let digits: Vec<_> = num.to_string().chars().map(|d| d.to_digit(10).unwrap()).collect();
If you wanted to return an iterator, you can then convert the Vec
back into an iterator:
fn digits(num: usize) -> impl Iterator<Item = u32> {
num.to_string()
.chars()
.map(|d| d.to_digit(10).unwrap())
.collect::<Vec<_>>()
.into_iter()
}
As for an alternate solution, there's the math way, stolen from the C++ question to create a vector:
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);
}
However, you might want to add all the special case logic for negative numbers, and testing wouldn't be a bad idea.
You might also want a fancy-pants iterator version:
fn digits(mut num: usize) -> impl Iterator<Item = usize> {
let mut divisor = 1;
while num >= divisor * 10 {
divisor *= 10;
}
std::iter::from_fn(move || {
if divisor == 0 {
None
} else {
let v = num / divisor;
num %= divisor;
divisor /= 10;
Some(v)
}
})
}
Or the completely custom type:
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);
}
See also: