Is it possible to conditionally apply iterator transformations? [duplicate] - iterator

I'm trying to switch behavior based on an Option input to a function. The idea is to iterate based on whether or not a given Option is present. Here's a minimal, if silly, example:
use std::iter;
fn main() {
let x: Option<i64> = None;
// Repeat x 5 times if present, otherwise count from 1 to 5
for i in match x {
None => 1..5,
Some(x) => iter::repeat(x).take(5),
} {
println!("{}", i);
}
}
I get an error:
error[E0308]: match arms have incompatible types
--> src/main.rs:7:14
|
7 | for i in match x {
| ______________^
8 | | None => 1..5,
9 | | Some(x) => iter::repeat(x).take(5),
| | ----------------------- match arm with an incompatible type
10 | | } {
| |_____^ expected struct `std::ops::Range`, found struct `std::iter::Take`
|
= note: expected type `std::ops::Range<{integer}>`
found type `std::iter::Take<std::iter::Repeat<i64>>`
This makes perfect sense, of course, but I'd really like to choose my iterator based on a condition, since the code in the for-loop is non-trivial and copy-pasting all of that just to change iterator selection would be pretty ugly and unmaintainable.
I tried using as Iterator<Item = i64> on both arms, but that gives me an error about unsized types because it's a trait object. Is there an easy way to go about this?
I could, of course, use .collect() since they return the same type and iterate over that vector. Which is a good quick fix, but for large lists seems a bit excessive.

The most straightforward solution is to use a trait object:
use std::iter;
fn main() {
let mut a;
let mut b;
let x: Option<i64> = None;
// Repeat x 5 times if present, otherwise count from 1 to 5
let iter: &mut dyn Iterator<Item = i64> = match x {
None => {
a = 1..5;
&mut a
}
Some(x) => {
b = iter::repeat(x).take(5);
&mut b
}
};
for i in iter {
println!("{}", i);
}
}
The main downside for this solution is that you have to allocate stack space for each concrete type you have. This also means variables for each type. A good thing is that only the used type needs to be initialized.
The same idea but requiring heap allocation is to use boxed trait objects:
use std::iter;
fn main() {
let x: Option<i64> = None;
// Repeat x 5 times if present, otherwise count from 1 to 5
let iter: Box<dyn Iterator<Item = i64>> = match x {
None => Box::new(1..5),
Some(x) => Box::new(iter::repeat(x).take(5)),
};
for i in iter {
println!("{}", i);
}
}
This is mostly useful when you want to return the iterator from a function. The stack space taken is a single pointer, and only the needed heap space will be allocated.
You can also use an enum for each possible concrete iterator.

The either crate provides the Either type. If both halves of Either are iterators, then so is the Either:
extern crate either;
use either::Either;
use std::iter;
fn main() {
let x: Option<i64> = None;
// Repeat x 5 times if present, otherwise count from 1 to 5
let iter = match x {
None => Either::Left(1..5),
Some(x) => Either::Right(iter::repeat(x).take(5)),
};
for i in iter {
println!("{}", i);
}
}
Like a previous answer, this still takes stack space for each concrete type you have. However, you don't need individual variables for each concrete value.
This type can also be returned from a function, unlike the trait object references. Compared to boxed trait objects, it will always use a fixed size on the stack, regardless of which concrete type was chosen.
You'll find this type (or semantic equivalent) in other places as well, such as futures::Either

Personally, rather than use Either, I often prefer to create a series of Option<Iterator> values that get chained together. Something like this:
playground
use std::iter;
fn main() {
let x: Option<i64> = None;
// Repeat x 5 times if present, otherwise count from 1 to 5
for i in pick(x) {
println!("{}", i);
}
}
fn pick(opt_x: Option<i64>) -> impl Iterator<Item = i64> {
let iter_a = if let None = opt_x {
Some(1..5)
} else {
None
};
let iter_b = if let Some(x) = opt_x {
Some(iter::repeat(x).take(5))
} else {
None
};
iter_a.into_iter().flatten().chain(iter_b.into_iter().flatten())
}
It's a bit less obvious than using Either, but it avoids another crate, and sometimes it works out quite elegantly.

Here is a variation of #Niko's brilliant solution using a single match expression instead of several if let expressions, which may be more convenient when dealing with more conditional cases:
use std::iter;
fn main() {
let x: Option<i64> = None;
// Repeat x 5 times if present, otherwise count from 1 to 5
for i in pick(x) {
println!("{}", i);
}
}
fn pick(opt_x: Option<i64>) -> impl Iterator<Item = i64> {
let mut iter_a = None;
let mut iter_b = None;
match opt_x {
None => iter_a = Some(1..5),
Some(x) => iter_b = Some(iter::repeat(x).take(5)),
}
iter_a.into_iter().flatten().chain(iter_b.into_iter().flatten())
}

Related

I need help refactoring for error handling in Rust

I would like to refactor this Rust code for calculating the largest series product and make it as efficient and elegant as possible. I feel that
lsp(string_digits: &str, span: usize) -> Result<u64, Error>
could be done in a way to make it much more elegant than it is right now. Could lsp be implemented with only one series of chained iterator methods?
#[derive(Debug, PartialEq)]
pub enum Error {
SpanTooLong,
InvalidDigit(char),
}
fn sp(w: &[u8]) -> u64 {
w.iter().fold(1u64, |acc, &d| acc * u64::from(d))
}
pub fn lsp(string_digits: &str, span: usize) -> Result<u64, Error> {
let invalid_chars = string_digits
.chars()
.filter(|ch| !ch.is_numeric())
.collect::<Vec<_>>();
if span > string_digits.len() {
return Err(Error::SpanTooLong);
} else if !invalid_chars.is_empty() {
return Err(Error::InvalidDigit(invalid_chars[0]));
} else if span == 0 || string_digits.is_empty() {
return Ok(1);
}
let vec_of_u8_digits = string_digits
.chars()
.map(|ch| ch.to_digit(10).unwrap() as u8)
.collect::<Vec<_>>();
let lsp = vec_of_u8_digits
.windows(span)
.max_by(|&w1, &w2| sp(w1).cmp(&sp(w2)))
.unwrap();
Ok(sp(lsp))
}
Not sure if this is the most elegant way, but I've given it a try, hope the new version is equivalent to the given program.
Two things will be needed in this case: First, we need a data structure that provides the sliding window "on the fly" and second a function that ends the iteration early if the conversion yields an error.
For the former I've chosen a VecDeque since span is dynamic. For the latter there is a function called process_results in the itertools crate. It converts an iterator over results to an iterator over the unwrapped type and stops iteration if an error is encountered.
I've also slightly changed the signature of sp to accept any iterator over u8.
This is the code:
use std::collections::VecDeque;
use itertools::process_results;
#[derive(Debug, PartialEq)]
pub enum Error {
SpanTooLong,
InvalidDigit(char),
}
fn sp(w: impl Iterator<Item=u8>) -> u64 {
w.fold(1u64, |acc, d| acc * u64::from(d))
}
pub fn lsp(string_digits: &str, span: usize) -> Result<u64, Error> {
if span > string_digits.len() {
return Err(Error::SpanTooLong);
} else if span == 0 || string_digits.is_empty() {
return Ok(1);
}
let mut init_state = VecDeque::new();
init_state.resize(span, 0);
process_results(string_digits.chars()
.map(|ch| ch.to_digit(10)
.map(|d| d as u8)
.ok_or(Error::InvalidDigit(ch))),
|digits|
digits.scan(init_state, |state, digit| {
state.pop_back();
state.push_front(digit);
Some(sp(state.iter().cloned()))
})
.max()
.unwrap()
)
}

Wrong number of lifetime parameters when using a modified `Chars` iterator

I want to implement the IntoIterator trait for a struct containing a String. The iterator is based on the chars() iterator, is supposed to count the '1' chars and accumulate the result. This is a simplified version of what I got so far:
use std::iter::Map;
use std::str::Chars;
fn main() {
let str_struct = StringStruct { system_string: String::from("1101") };
for a in str_struct {
println!("{}", a);
}
}
struct StringStruct {
system_string: String
}
impl IntoIterator for StringStruct {
type Item = u32;
type IntoIter = Map<Chars, Fn(char) -> u32>;
fn into_iter(self) -> Self::IntoIter {
let count = 0;
return self.system_string.chars().map(|c| match c {
Some('1') => {
count += 1;
return Some(count);
},
Some(chr) => return Some(count),
None => return None
});
}
}
Expected output: 1, 2, 2, 3
This fails with:
error[E0107]: wrong number of lifetime parameters: expected 1, found 0
--> src/main.rs:17:25
|
17 | type IntoIter = Map<Chars, Fn(char) -> u32>;
| ^^^^^ expected 1 lifetime parameter
The chars iterator should have the same lifetime as the StringStruct::system_string, but I have no idea how to express this or if this approach is viable at all.
To answer the question you asked, I'd recommend to impl IntoIterator for &StringStruct (a reference to a StringStruct instead of the struct directly). The code would look like this:
impl<'a> IntoIterator for &'a StringStruct {
type Item = u32;
type IntoIter = Map<Chars<'a>, Fn(char) -> u32>;
// ...
}
However, you will notice many more errors that have a different origin afterwards. The next error that pops up is that Fn(char) -> u32 does not have a constant size at compile time.
The problem is that you try to name the type of your closure by writing Fn(char) -> u32. But this is not the type of your closure, but merely a trait which is implemented by the closure. The type of a closure can't be named (sometimes called "Voldemort type").
This means that, right now, you can't specify the type of a Map<_, _> object. This is a known issue; the recently accepted impl Trait-RFC might offer a workaround for cases like this. But right now, it's not possible, sorry.
So how to solve it then? You need to create your own type that implements Iterator and use it instead of Map<_, _>. Note that you can still use the Chars iterator. Here is the full solution:
struct StringStructIter<'a> {
chars: Chars<'a>,
count: u32,
}
impl<'a> Iterator for StringStructIter<'a> {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
self.chars.next().map(|c| {
if c == '1' {
self.count += 1;
}
self.count
})
}
}
impl<'a> IntoIterator for &'a StringStruct {
type Item = u32;
type IntoIter = StringStructIter<'a>;
fn into_iter(self) -> Self::IntoIter {
StringStructIter {
chars: self.system_string.chars(),
count: 0,
}
}
}
fn main() {
let str_struct = StringStruct { system_string: String::from("1101") };
for a in &str_struct {
println!("{}", a);
}
}
And just a small note: an explicit return when not necessary is considered bad style in Rust. Better stick to rule and write idiomatic code by removing return whenever possible ;-)

Writing an iterator [duplicate]

This question already has answers here:
How to implement Iterator and IntoIterator for a simple struct?
(2 answers)
Closed 4 years ago.
Editor's note: This code example is from a version of Rust prior to 1.0 and is not valid Rust 1.0 code. Updated versions of this code no longer produce an error due to changes how for loops are implemented.
I'm writing a Vector struct in Rust.
pub struct Vector {
pub x: f32,
pub y: f32,
pub z: f32,
curr: uint
}
And I'd like to write a simple iterator for it, so that I can iterate over the elements of the vector. It's occasionally useful, plus I know next to nothing about iterators in Rust.
Here's what I've got at the moment.
impl Iterator<f32> for Vector {
fn next(&mut self) -> Option<f32> {
let new_next : Option<f32> = match self.curr {
0 => Some(self.x),
1 => Some(self.y),
2 => Some(self.z),
_ => None
};
let new_curr = (self.curr + 1) % 4;
mem::replace(&mut self.curr, new_curr);
new_next
}
}
Now ideally I'd like to be able to use this like:
let u = Vector::new(0.0f32, 0.0f32, 0.0f32);
for element in u {
///
}
However, I get the following compiler error:
error: cannot borrow immutable local variable `u` as mutable
So I'm stumped. After a couple hours of Googling, I couldn't come up with anything. I feel like I'm missing something huge.
Are you sure you really want the Vector itself to be an iterator? Usually structures and iterators into them are separate. Consider something like this:
pub struct Vector {
pub x: f32,
pub y: f32,
pub z: f32,
}
pub struct VectorIter<'a> {
vector: &'a Vector,
cur: usize,
}
impl<'a> Iterator for VectorIter<'a> {
type Item = f32;
fn next(&mut self) -> Option<f32> {
let r = match self.cur {
0 => self.vector.x,
1 => self.vector.y,
2 => self.vector.z,
_ => return None,
};
self.cur += 1;
Some(r)
}
}
impl Vector {
fn iter(&self) -> VectorIter {
VectorIter {
vector: self,
cur: 0,
}
}
}
fn main() {
let v = Vector { x: 1.0, y: 2.0, z: 3.0 };
for c in v.iter() {
println!("{}", c);
}
}
Because Vector is very simple, it can derive Copy, and its iterator can take it by value:
#[derive(Copy, Clone)]
pub struct Vector {
pub x: f32,
pub y: f32,
pub z: f32,
}
pub struct VectorIter {
vector: Vector,
cur: usize,
}
impl Iterator for VectorIter {
type Item = f32;
fn next(&mut self) -> Option<f32> {
let r = match self.cur {
0 => self.vector.x,
1 => self.vector.y,
2 => self.vector.z,
_ => return None,
};
self.cur += 1;
Some(r)
}
}
impl Vector {
fn iter(&self) -> VectorIter {
VectorIter {
vector: *self,
cur: 0,
}
}
}
fn main() {
let v = Vector { x: 1.0, y: 2.0, z: 3.0 };
for c in v.iter() {
println!("{}", c);
}
}
This variant is probably better unless your Vector contains something other than coordinates. This variant is more flexible because it does not tie the iterator with the iterable, but on the other hand, exactly because of the same reason it may be undesirable (with Copy you can change the original value, and the iterator won't reflect it; without Copy and with references you won't be able to change the original value at all). The semantics you would want to use heavily depends on your use cases.
Editor's note: This answer is no longer useful as of Rust 1.0 due to changes how the for loop works.
Vladimir Matveev's answer is correct and explains what you should do. I'd like to add on by explaining your error a bit more.
error: cannot borrow immutable local variable u as mutable
When you are iterating over something, you need to mutate something that tracks where you are. In your code, that's done by:
mem::replace(&mut self.curr, new_curr);
And Rust knows which thing you want to mutate because the method signature for next indicates it:
fn next(&mut self) -> Option<f32>
The problem is that your object is not mutable:
let u = Vector::new(0.0f32, 0.0f32, 0.0f32);
If you change your code to
let mut u = Vector::new(0.0f32, 0.0f32, 0.0f32);
I'd expect your code to work as-is. All that being said, a separate iterator is probably the right way to go. However, you'll know more than we do about your code!

Changing a enum's field in Rust

I am very new to Rust but I am trying to work out how to modify an instance of an enum. I need to use managed boxes for other reasons, but it seems to make changing an enum's field hard.
#[feature(managed_boxes)];
enum State { A(int), B }
fn main() {
let mut state = #A(123);
match *state {
A(ref mut i) => { *i = 456 }
B => { }
}
println!("{:?}", state)
}
I get the error cannot borrow immutable anonymous field as mutable. The mut seems to only say that state, the variable, is mutable. I want to tell Rust the whole thing is mutable. I find forced immutability one of the most annoying things of Rust.
Some time ago managed boxed had their own "hierarchy" of mutability. The following code used to work then:
#[feature(managed_boxes)];
enum State { A(int), B }
fn main() {
let state = #mut A(123);
match *state {
A(ref mut i) => { *i = 456 }
B => { }
}
println!("{:?}", state)
}
But managed boxes are scheduled to be removed from the language. In current version of Rust #mut is not a valid token. You have to use RefCell, a mutable cell which provides mutability inside managed pointers. Currently it looks somewhat like this:
#[feature(managed_boxes)];
use std::cell::RefCell;
enum State { A(int), B }
fn main() {
let state = #RefCell::new(A(123));
{
let mut r = state.borrow_mut();
match r.get() {
&A(ref mut i) => { *i = 456 }
&B => { }
}
}
println!("{:?}", state)
}
You will get rather extensive output on the terminal though, because it will print internals of RefCell structure. See documentation on std::cell module for more information on cells and how to use them.
In the future Rust won't have special syntax for managed boxes at all. Garbage collection will be implemented in libraries. I believe the code will look like this (Rust authors, please correct me if I'm wrong):
use std::cell::RefCell;
enum State { A(int), B }
fn main() {
// state is of type Gc<RefCell<State>>
let state = box(Gc) RefCell::new(A(123));
// Dereference will work for library pointer types, not sure about autodereference
let mut r = (*state).borrow_mut();
match r.get() {
&A(ref mut i) => { *i = 456 }
&B => { }
}
println!("{:?}", *state)
}

How do I emulate Lisp (apply) or (curry) in Rust?

I'm porting QuickCheck to Rust, and I've written everything except for_all as I'm not sure what the type signature should be.
I know that in general, for_all will accept a property lambda and a collection of generator lambdas. It will evaluate the generators in order to create a random test case to give the property as input.
It should print +++ OK, passed 100 tests. if the property returns true, otherwise, it should print *** Failed! and print the offending test case values.
In Rust, all functions take a fixed number of parameters, so there's no such thing as an equivalent to Lisp's apply in the general case, but macros can provide you with the abstraction you desire. You can write:
macro_rules! for_all {
( $tester:expr, $( $generator:expr ),* ) => {
$tester( $($generator() ),* )
}
}
Then, for_all!(|a, b| a + b, || 4, || 7) produces 11.
Good luck with your project!
Editor's note: This answer is from a version of Rust prior to 1.0 and contains code that is not syntactically valid in Rust 1.0.
If all you need is a way to define apply, try Rust's macro-by-example syntax extensions:
fn main() {
#macro[[#apply[f, [x, ...]], f(x, ...)]];
fn add(a: int, b: int) -> int { a + b }
assert (#apply[add, [1, 15]] == 16);
}
The above code is from the Rust test suite.
Sadly, the documentation on syntax extensions is a bit sparse at the moment. The Rust reference manual is probably your best bet--although the example it gives (of apply, no less!) is outdated, so I'm not sure how much of its information can be trusted.
Update:
All that's left is figuring out how to wrap add ... assert in a function with the right type signature that accepts arbitrary generators.
I'm still not sure exactly how you're putting this all together, but here's a function that accepts any function that produces an int:
use std;
import std::rand;
fn assert_even(num_gen: fn() -> int) -> (bool, int) {
let num = num_gen();
ret (num % 2 == 0, num);
}
fn main() {
let rng = rand::mk_rng();
let gen_even = {|| (rng.next() as int) * 2};
log(error, assert_even(gen_even));
}
However, working with numbers in Rust is sort of a pain at the moment, and if you want to generalize assert_even to any numeric type you'll have to define interfaces/implementations and then declare assert_even with a bounded generic type:
use std;
import std::rand;
iface is_even { fn is_even() -> bool; }
impl of is_even for int { fn is_even() -> bool { self % 2 == 0 } }
impl of is_even for u32 { fn is_even() -> bool { self % 2u == 0u } }
fn assert_even<T: is_even>(num_gen: fn() -> T) -> (bool, T) {
let num = num_gen();
ret (num.is_even(), num);
}
fn main() {
let rng = rand::mk_rng();
let gen_even_int = {|| (rng.next() as int) * 2};
let gen_even_u32 = {|| rng.next() * 2u};
log(error, assert_even(gen_even_int));
log(error, assert_even(gen_even_u32));
}
Side note: if you're interested in testing, you should check out Rust's typestate facilities. See the Rust manual here for an example of what typestate does and the ways in which it is capable of enforcing program correctness. The way I understand it, it's basically a more powerful version of Eiffel's design by contract.
Update 2:
for_all accepts a single property (e.g. is_even or divisible_by) and a collection of generator functions. The generators are lambdas which return random values to pass as input to the property, e.g. [gen_int] for is_even or [gen_int, gen_int] for divisible_by. for_all will call the property using the generated values as a test case, printing +++ OK, passed 100 tests if the property returns true for 100 random test cases, or *** Failed! {test_case} if one of the test cases fails.
This complete source file should fully demonstrate the behavior that you're looking for, hopefully (the definition of for_all is near the very bottom):
use std;
import std::rand;
import std::io::println;
iface is_even { fn is_even() -> bool; }
impl of is_even for int { fn is_even() -> bool { self % 2 == 0 } }
fn main() {
let rng = rand::mk_rng();
// Cast to int here because u32 is lame
let gen_even = {|| (rng.next() as int) * 2};
let gen_float = {|| rng.next_float()};
// Accepts generators that produce types that implement the is_even iface
fn assert_even<T: is_even>(num_gen: fn() -> T) -> bool {
let num = num_gen();
let prop_holds = num.is_even();
if !prop_holds {
println(#fmt("Failure: %? is not even", num));
}
ret prop_holds;
}
fn assert_divisible(num_gen1: fn() -> float,
num_gen2: fn() -> float) -> bool {
let dividend = num_gen1(),
divisor = num_gen2();
let prop_holds = dividend / divisor == 0f;
if !prop_holds {
println(#fmt("Failure: %? are not divisible", (dividend, divisor)));
}
ret prop_holds;
}
// Begin anonymous closure here
#macro[[#for_all[prop, [gen, ...]], {||
let passed_tests = 0;
let prop_holds = true;
// Nice iterators and break/continue are still being implemented,
// so this loop is a bit crude.
while passed_tests < 100 && prop_holds {
prop_holds = prop(gen, ...);
if prop_holds { passed_tests += 1; }
}
println(#fmt("Tests passed: %d", passed_tests));
ret 0; // Necessary to infer type of #for_all, might be a compiler bug
}()]]; // Close anonymous closure and self-execute, then close #macro
#for_all[assert_even, [gen_even]];
#for_all[assert_divisible, [gen_float, gen_float]];
}
One more thing: the syntax extension mechanism is still fairly unpolished, so it's not possible to import macros from different crates. Until then, the definition of #for_all will have to appear in the file in which it is invoked.
Can you describe precisely what you want? I think what you're asking for is something like this:
fn for_all<A>(test: fn(A) -> bool, generators: &[fn() -> A]) -> bool {
generators.iter().all(|gen| test(gen()))
}
fn main() {
let generators: Vec<fn() -> (i32, i32)> = vec![
|| (1, 2),
|| (2, 3),
|| (3, 4),
];
for_all(|(a, b)| a < b, &generators);
}