pub fn primes_up_to(upper_bound: u64) -> Vec<u64> {
let mut numbers: Vec<_> = (0..=upper_bound).map(Option::from).collect();
let upper_bound = upper_bound as usize;
(2..numbers.len())
.filter_map(|i| {
let prime = numbers[i].take()? as usize;
(prime * prime..=upper_bound)
.step_by(prime)
.for_each(|j| numbers[j] = None);
Some(prime as u64)
})
.collect()
}
This approach starts by defining a Vec
of Some
values from 0
through the upper bound.
To minimize type conversions, the upper bound is redefined as a usize
.
A Range is defined that goes from 2
through the length of the Vec
.
Each number from the range is passed to the filter_map()
.
The closure (also known as a lambda) in the body of the filter_map()
uses the take()
method, combined with the
unwrap operator (?
), to get the element value in the Vec
at the index of the number passed in from the range.
If the element value is None
, then no further processing happens in the lambda for that iteration.
If the element value is Some
number, then an inner range is defined, starting from the element value times itself and going through the upper bound.
The step_by()
method is used to traverse the range in steps the size of the element value.
Each number from the inner range is passed to the for_each()
method.
The lambda inside the for_each
sets None
as the value for the element in the Vec
at the index of the value passed in.
After the inner range is done, the filter_map()
lambda returns the element value rewrapped in a Some
as type u64
.
After the outer range is done, all of the Some
values are collected from the Vec
and returned.
Type inference is used to return the values as a type Vec<u64>
.