Let's first understand, how to traverse range with accessing elements:
immutable:
use stl::*;
let arr = [1, 2, 3];
let start = arr.start();
while arr.is_end(&start) {
println!("{}", arr.at(&start));
}
// If end position is known one can also do:
let start = arr.start();
let end = arr.end();
while start != end {
println!("{}", arr.at(&start));
}
mutable:
let mut arr = [1, 2, 3];
let start = arr.start();
while arr.is_end(&start) {
arr.at_mut(&start) = 3;
}
rs-stl provides 3 ways to call an algorithm:
algo::
rng::
- infix
algo::
version accepts start
and end
positions explictly, to work on given
subrange of range. For example:
use stl::*;
let arr = [1, 2, 3, 4, 5];
let i = arr.after_n(arr.start(), 2);
let j = arr.end();
let cnt = algo::count_if(&arr, i, j, |x| x % 2 == 1);
assert_eq!(cnt, 2)
The above algorithms work on [i, j)
positions of arr
rather than working
on full array arr
.
This version algorithm is highly composable, and thus really useful while writing
new generic algorithms. For normal cases, one may use rng
and infix
versions.
rng::
version just accepts the given range for working, and work over full
range. For example:
use stl::*;
let arr = [1, 2, 3, 4, 5];
let cnt = rng::count_if(&arr, |x| x % 2 == 1);
assert_eq!(cnt, 3)
infix version comes under stl::rng::infix
module, that enables algorithms
to be used as methods. All rng
algorithms doesn't support infix version and
thus look into stl::rng
module's algorithm document to know if that supports
infix version.
use stl::*;
use rng::infix::*;
let arr = [1, 2, 3, 4, 5];
let cnt = arr.count_if(|x| x % 2 == 1);
assert_eq!(cnt, 3)
For creating view from a given range, one can use .view()
method or .view_mut()
method.
immutable view:
let arr = [1, 2, 3];
let v = arr.view();
mutable view:
let mut arr = [1, 2, 3];
let v = arr.view_mut();
Here v doesn't consume arr, but do immutable and mutable borrow of arr respectively.
View factories are functions that returns a view without taking a range/view as argument.
let ints = view::ints(0); // 0, 1, 2, 3, ...
View adaptors are functions that accept view as an argument by value and returns a new view by consuming given view. For example:
let ints_3 = view::ints(0)
.take(3); // 0, 1, 2
In above example, take is an adaptor.
As views are also ranges, they can be used with the algorithms described above:
use stl::*;
use rng::infix::*;
let mut arr = [(1, 2), (2, 1)];
arr
.view()
.map(|x| x.1)
.sort_range();
assert_eq!(arr, [(2, 1), (1, 2)]);
In above example, .view().map(...)
gives a view that is passed to sort_range
algorithm. As this view mutably borrows arr, arr is sorted.
This enables inplace mutation of ranges with functional style programming.
For working with for loops iterators are just great and they have their own
usecases. rs-stl provides, iter
method to traverse InputRange
as Iterator
.
use stl::*;
use rng::infix::*;
let mut sum = 0;
for e in view::single(2).iter() {
sum += e;
}
assert_eq!(sum, 2);