Iterators
take() and skip()
The .take(n) and .skip(n) adapters slice an iterator by element count: .take(n) yields at most the first n elements, and .skip(n) discards the first n elements before yielding the remainder.
Signatures
fn take(self, n: usize) -> Take<Self>
where
Self: Sized;
fn skip(self, n: usize) -> Skip<Self>
where
Self: Sized;
Source: [ 10, 20, 30, 40, 50, 60 ]
└───┬───┘ └───────┬───┘
.skip(2) .take(3)
│
▼
Output: [ 30, 40, 50 ]
If the underlying iterator has fewer than n elements:
.take(n)yields all available elements and stops cleanly without panicking..skip(n)exhausts the iterator and yields0elements without panicking.
Pagination with .skip(offset).take(limit)
Combining .skip(offset) followed by .take(page_size) implements bounds-safe pagination over any iterator:
fn get_page<T: Copy>(items: &[T], page_index: usize, page_size: usize) -> Vec<T> {
let offset = page_index * page_size;
items.iter().copied().skip(offset).take(page_size).collect()
}
fn main() {
let dataset = [10, 20, 30, 40, 50, 60, 70];
println!("Page 0: {:?}", get_page(&dataset, 0, 3));
println!("Page 1: {:?}", get_page(&dataset, 1, 3));
println!("Page 2: {:?}", get_page(&dataset, 2, 3));
println!("Page 9: {:?}", get_page(&dataset, 9, 3));
}
Page 0: [10, 20, 30]
Page 1: [40, 50, 60]
Page 2: [70]
Page 9: []
Bounding Infinite Iterators with .take(n)
Because Rust ranges without an upper bound (0..) and generators like std::iter::repeat and std::iter::successors produce infinite sequences, .take(n) is used to turn an infinite iterator into a finite one:
use std::iter::successors;
fn main() {
// Powers of 2 starting at 1:
let powers_of_two: Vec<u64> = successors(Some(1_u64), |&n| Some(n * 2))
.take(8)
.collect();
println!("{powers_of_two:?}");
}
[1, 2, 4, 8, 16, 32, 64, 128]