How to iterate over a slice of mapped slices? - rust

Here's an example of what I'm trying to do:
for &xs in &[&[1, 2, 3].iter().map(|x| x + 1)] {
for &x in xs {
println!("{}", x);
}
}
This gives me the following error:
error[E0277]: the trait bound `&std::iter::Map<std::slice::Iter<'_, {integer}>, [closure#src/main.rs:2:40: 2:49]>: std::iter::Iterator` is not satisfied
--> src/main.rs:3:9
|
3 | / for &x in xs {
4 | | println!("{}", x);
5 | | }
| |_________^ the trait `std::iter::Iterator` is not implemented for `&std::iter::Map<std::slice::Iter<'_, {integer}>, [closure#src/main.rs:2:40: 2:49]>`
|
= note: `&std::iter::Map<std::slice::Iter<'_, {integer}>, [closure#src/main.rs:2:40: 2:49]>` is not an iterator; maybe try calling `.iter()` or a similar method
= note: required by `std::iter::IntoIterator::into_iter`
...which is very surprising, because I clearly see how std::Iter::Map implements Iterator.
Why does it complain and how to iterate over a slice of mapped slices?

&T can't be iterated as next mutates.
Thus if you have a &Map<_, _>, you can't iterate it.
You might not realize that &[1,2,3].iter().map(|&x| x+1) means
&([1,2,3].iter().map(|&x| x+1))
giving the reference.
Using for &xs in &[&mut ...] won't work either, as it requires moving xs out of an immutable reference. There is also currently no by-value iterator over fixed length arrays. I believe the easiest solution is
for xs in &mut [&mut [1, 2, 3].iter().map(|&x| x+1)] {
for x in xs {
println!("{}", x);
}
}
Note that this also requires fixing a problem with the map call, which didn't dereference its input.

Related

How properly use Iterator::chain in rust

I was trying to use Chain in Rust and encountered a problem that seems strange to me. I tried two code snippets that one of them works and the other doesn't. I tried to figure out the problem from the error message emitted by the compiler but couldn't find anything useful.
Snippet 1
fn main() {
let v: Vec<_> = (1..5).collect();
let u = v.iter().chain([6, 7, 8, 9, 10].iter().map(|i| i ));
u.for_each(|i| println!("{i}"));
}
Snippet 2
fn main() {
let v: Vec<_> = (1..5).collect();
let u = v.iter().chain([6, 7, 8, 9, 10].iter().map(|i| i+1 ));
u.for_each(|i| println!("{i}"));
}
The first snippet runs successfully but the second fails. The error message is:
Compiling playground v0.0.1 (/playground)
error[E0271]: type mismatch resolving `<[closure#src/main.rs:5:56: 5:63] as FnOnce<(&{integer},)>>::Output == &{integer}`
--> src/main.rs:5:28
|
5 | let u = v.iter().chain([6, 7, 8, 9, 10].iter().map(|i| i+1 ));
| ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&{integer}`, found integer
| |
| required by a bound introduced by this call
|
= note: required because of the requirements on the impl of `Iterator` for `Map<std::slice::Iter<'_, {integer}>, [closure#src/main.rs:5:56: 5:63]>`
note: required by a bound in `std::iter::Iterator::chain`
error[E0599]: the method `for_each` exists for struct `std::iter::Chain<std::slice::Iter<'_, {integer}>, Map<std::slice::Iter<'_, {integer}>, [closure#src/main.rs:5:56: 5:63]>>`, but its trait bounds were not satisfied
--> src/main.rs:6:7
|
6 | u.for_each(|i| println!("{i}"));
| ^^^^^^^^ method cannot be called on `std::iter::Chain<std::slice::Iter<'_, {integer}>, Map<std::slice::Iter<'_, {integer}>, [closure#src/main.rs:5:56: 5:63]>>` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`<Map<std::slice::Iter<'_, {integer}>, [closure#src/main.rs:5:56: 5:63]> as Iterator>::Item = &{integer}`
which is required by `std::iter::Chain<std::slice::Iter<'_, {integer}>, Map<std::slice::Iter<'_, {integer}>, [closure#src/main.rs:5:56: 5:63]>>: Iterator`
`std::iter::Chain<std::slice::Iter<'_, {integer}>, Map<std::slice::Iter<'_, {integer}>, [closure#src/main.rs:5:56: 5:63]>>: Iterator`
which is required by `&mut std::iter::Chain<std::slice::Iter<'_, {integer}>, Map<std::slice::Iter<'_, {integer}>, [closure#src/main.rs:5:56: 5:63]>>: Iterator`
Some errors have detailed explanations: E0271, E0599.
For more information about an error, try `rustc --explain E0271`.
error: could not compile `playground` due to 2 previous errors
I'm new to Rust and not familiar with many details. Can someone explain to me what's the problem here? Why changing the i to i+1 can cause a compile-time error?
This succeeds in the first case because both iterators are producing &i32 items. However, in the second case the first iterator is producing &i32 items, while the second iterator is producing i32 items -- the addition operation auto-derefs i and produces an integer. To chain two iterators, the item types must match exactly.
To clarify, the closures given to map in both snippets differ in their signature, which may be surprising since they look nearly identical!
|i| i accepts an &i32 and returns that &i32. In snippet 1, this is equivalent to |i: &i32| -> &i32 { i }.
|i| i + 1 accepts an &i32 and returns an i32, which is not the same type. In snippet 2, this is equivalent to |i: &i32| -> i32 { *i + 1 }.
To fix this, use the copied utility to convert the first iterator from &i32 items to i32 items by copy, which will match the type of the second iterator, allowing chaining:
fn main() {
let v: Vec<_> = (1..5).collect();
let u = v.iter().copied().chain([6, 7, 8, 9, 10].iter().map(|i| i+1 ));
u.for_each(|i| println!("{i}"));
}
Alternatively, convert the Vec to an interator with into_iter, which will consume the Vec and produce its values directly (not as references).
fn main() {
let v: Vec<_> = (1..5).collect();
let u = v.into_iter().chain([6, 7, 8, 9, 10].iter().map(|i| i+1 ));
u.for_each(|i| println!("{i}"));
}
Type inference can be handy, but it can also hide information from you. When you run into "type mismatch" errors like this and you can't figure them out, a good way to diagnose the problem is to start adding type annotations based on what you think the types actually are. Either an added type annotation will fix the problem by forcing a type that was incorrectly inferred, or Rust will complain that the type annotation doesn't match an actual type, which will expose your incorrect assumption and from there you should be able to solve the problem.
In this particular case, adding the return type annotation -> &i32 to the second closure would have led to a much more understandable error:
error[E0308]: mismatched types
--> src/main.rs:6:28
|
6 | .map(|i| -> &i32 { i+1 } )
| ^^^
| |
| expected `&i32`, found integer
| help: consider borrowing here: `&(i+1)`
The compiler's suggestion is incorrect, but this makes the situation much clearer and helps you see that your closure was returning i32 when you thought from your first snippet that it would return &i32.

Unexpected "method not found" compiler error

This question arises from my use (in a toy project to learn Rust) of cartesian_product from itertools together with into_par_iter from Rayon. My question is less about this particular code and more a question about reading rustc error messages, and the Rust library documentation.
This works as expected:
fn main() {
let it = 0..15;
it.into_par_iter().for_each(|x| println!("{:?}", x));
}
But the code below fails to compile with the error indicated. The documentation for the Product returned by cartesian_product includes an implementation of Iterator, so I would have expected the into_par_iter method call to type check, but such is not the case.
Here's the failing code and the resulting error message:
fn main() {
let it = (0..15).cartesian_product(0..8);
it.into_par_iter().for_each(|x| println!("{:?}", x));
}
Compiling iters v0.1.0 (D:\rust\iters)
error[E0599]: no method named `into_par_iter` found for struct `itertools::adaptors::Product<std::ops::Range<{integer}>, std::ops::Range<{integer}>>` in the current scope
--> src\main.rs:8:8
|
8 | it.into_par_iter().for_each(|x| println!("{:?}", x));
| ^^^^^^^^^^^^^ method not found in `itertools::adaptors::Product<std::ops::Range<{integer}>, std::ops::Range<{integer}>>`
|
::: D:\rust\dot.cargo\registry\src\github.com-1ecc6299db9ec823\itertools-0.9.0\src\adaptors\mod.rs:288:1
|
288 | / pub struct Product<I, J>
289 | | where I: Iterator
290 | | {
291 | | a: I,
... |
294 | | b_orig: J,
295 | | }
| | -
| | |
| |_doesn't satisfy `_: rayon::iter::IntoParallelIterator`
| doesn't satisfy `_: rayon::iter::ParallelIterator`
|
= note: the method `into_par_iter` exists but the following trait bounds were not satisfied:
`itertools::adaptors::Product<std::ops::Range<{integer}>, std::ops::Range<{integer}>>: rayon::iter::ParallelIterator`
which is required by `itertools::adaptors::Product<std::ops::Range<{integer}>, std::ops::Range<{integer}>>: rayon::iter::IntoParallelIterator`
`&itertools::adaptors::Product<std::ops::Range<{integer}>, std::ops::Range<{integer}>>: rayon::iter::ParallelIterator`
which is required by `&itertools::adaptors::Product<std::ops::Range<{integer}>, std::ops::Range<{integer}>>: rayon::iter::IntoParallelIterator`
`&mut itertools::adaptors::Product<std::ops::Range<{integer}>, std::ops::Range<{integer}>>: rayon::iter::ParallelIterator`
which is required by `&mut itertools::adaptors::Product<std::ops::Range<{integer}>, std::ops::Range<{integer}>>: rayon::iter::IntoParallelIterator`
itertools::Itertools::cartesian_product returns a value of type itertools::Product, which implements std's Iterator.
However, Rayon can't just work with any type that implements Iterator - it must also implement rayon::ParallelIterator. Rayon happens to provide implementations of ParallelIterator for most std iterators, but it can't implement them for structs in another crate (like itertools) without depending on that crate. Similarly, itertools couldn't implement rayon::ParallelIterator for its types without depending on rayon.
Instead, you can duplicate the functionality of Itertools::cartesian_product yourself using Rayon's API:
use rayon::iter::{ParallelIterator, IntoParallelIterator};
fn main() {
(0..15).into_par_iter()
.flat_map(|i| (0..8).into_par_iter().map(move |j| (i, j)))
.for_each(|x| println!("{:?}", x));
}
Alternatively, you can start with an iterator of length (15 * 8) and then use division and remainder to break it down into tuples:
use rayon::iter::{ParallelIterator, IntoParallelIterator};
fn main() {
let it = (0 .. 15 * 8).into_par_iter().map(|x| (x / 8, x % 8));
it.for_each(|x| println!("{:?}", x));
}

How to create a function that creates a Cartesian product Iterator from an Iterator of Iterators?

If I want to create a Cartesian product of a list of lists in Haskell, I can do this:
product [] = [[]]
product (xs:xss) = concatMap (\k -> map (k:) (product1 xss)) xs
or even this:
sequence xss
I'm trying to implement an efficient iterator that would do the same in Rust, but I'm not sure what is wrong with my attempt:
use std::iter::{empty, once};
fn product<T, I, V>(xss: I) -> Box<Iterator<Item = Iterator<Item = T>>>
where
T: Clone,
V: IntoIterator<Item = T>,
I: IntoIterator<Item = V>,
{
Box::new(xss.into_iter().fold(once(empty()), |acc, xs| {
xs.into_iter().flat_map(|x| acc.map(|ys| ys.chain(once(x))))
}))
}
fn main() {
let data = vec![[1, 2, 3], [10, 20, 30], [100, 200, 300]];
let it: Vec<Vec<u32>> = product(data).collect();
println!("{:?}", it);
}
(playground)
Produces these errors:
error[E0308]: mismatched types
--> src/main.rs:10:9
|
10 | xs.into_iter().flat_map(|x| acc.map(|ys| ys.chain(once(x))))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::iter::Once`, found struct `std::iter::FlatMap`
|
= note: expected type `std::iter::Once<std::iter::Empty<T>>`
found type `std::iter::FlatMap<<V as std::iter::IntoIterator>::IntoIter, std::iter::Map<std::iter::Once<std::iter::Empty<T>>, [closure#src/main.rs:10:45: 10:67 x:_]>, [closure#src/main.rs:10:33: 10:68 acc:_]>`
error[E0271]: type mismatch resolving `<std::iter::Once<std::iter::Empty<T>> as std::iter::Iterator>::Item == std::iter::Iterator<Item=T>`
--> src/main.rs:9:5
|
9 | / Box::new(xss.into_iter().fold(once(empty()), |acc, xs| {
10 | | xs.into_iter().flat_map(|x| acc.map(|ys| ys.chain(once(x))))
11 | | }))
| |_______^ expected struct `std::iter::Empty`, found trait std::iter::Iterator
|
= note: expected type `std::iter::Empty<T>`
found type `std::iter::Iterator<Item=T>`
= note: required for the cast to the object type `std::iter::Iterator<Item=std::iter::Iterator<Item=T>>`
error[E0277]: the trait bound `[{integer}; 3]: std::iter::Iterator` is not satisfied
--> src/main.rs:16:29
|
16 | let it: Vec<Vec<u32>> = product(data).collect();
| ^^^^^^^ `[{integer}; 3]` is not an iterator; maybe try calling `.iter()` or a similar method
|
= help: the trait `std::iter::Iterator` is not implemented for `[{integer}; 3]`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `[{integer}; 3]`
= note: required by `product`
error: the `collect` method cannot be invoked on a trait object
--> src/main.rs:16:43
|
16 | let it: Vec<Vec<u32>> = product(data).collect();
| ^^^^^^^
The first error is giving me the feeling that Rust cannot even create a lazily consumed iterator with fold because Empty<T> is an Iterator<Item = T> (at least conceptually), but I hope I'm wrong.
For what its worth, the Itertools crate implements a workable cartesian product function:
use itertools::Itertools;
let it = (0..2).cartesian_product("αβ".chars());
itertools::assert_equal(it, vec![(0, 'α'), (0, 'β'), (1, 'α'), (1, 'β')]);
The first reason your approach is bound to fail is because you're trying to transpose an algorithm designed to work on lists into an algorithm working on iterators. Lists are suitable for a functional approach, iterators aren't, because they have a state. The next(&mut self) function won't return the same value each time it's called with the same argument, whereas a next(x:xs) function will. This is the reason why the implementation found in itertools clones iterators: to save their initial state and recover it for the next iteration over the set.
The second reason, the one behind the error messages, is that you're fighting against Rust's type system. The result values of all your calls to iterator functions (fold, flat_map, etc.) aren't trait objects but 'concrete types'. For instance iterator.fold(init, fn)'s result type is init's type. That's why the compiler complains when you pass fold a lambda that doesn't return a std::iter::Empty<T>.
But it gets worse. You could imagine to coerce or cast that std::iter::Empty<T> into a trait object. Alas, object safety is required. To put it in a nutshell, "A good intuition is “except in special circumstances, if your trait’s method uses Self, it is not object-safe.". But iterators' main method is next(&mut self).

Print sliced vector results in "Sized is not satisfied"

I am trying to slice a vector and print it simultaneously in Rust. This is my code:
fn main() {
let a = vec![1, 2, 3, 4];
println!("{:?}", a[1..2]);
}
Error:
error[E0277]: the trait bound `[{integer}]: std::marker::Sized` is not satisfied
--> src/main.rs:6:5
|
6 | println!("{:?}", a[1..3]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `[{integer}]: std::marker::Sized` not satisfied
|
= note: `[{integer}]` does not have a constant size known at compile-time
= note: required by `std::fmt::ArgumentV1::new`
= note: this error originates in a macro outside of the current crate
How do I print this sliced vector?
You need to use a reference; it worked for me in Rust 1.13.
println!("{:?}", &a[1..3]);

Slice and iter() simultaneously

I am trying to figure out why this does not work (Playground):
fn main() {
let a = vec![1, 2, 3, 4];
let b = a.clone();
// slice and iter (wrong way)
let s: i32 = &a[1..a.len()].iter()
.zip(&b[1..b.len()].iter())
.map(|(x, y)| x * y)
.sum();
println!("{}", s);
}
Error:
rustc 1.13.0 (2c6933acc 2016-11-07)
error[E0277]: the trait bound `&std::slice::Iter<'_, {integer}>: std::iter::Iterator` is not satisfied
--> <anon>:6:10
|
6 | .zip(&b[1..b.len()].iter())
| ^^^ trait `&std::slice::Iter<'_, {integer}>: std::iter::Iterator` not satisfied
|
= note: `&std::slice::Iter<'_, {integer}>` is not an iterator; maybe try calling `.iter()` or a similar method
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&std::slice::Iter<'_, {integer}>`
error: no method named `map` found for type `std::iter::Zip<std::slice::Iter<'_, {integer}>, &std::slice::Iter<'_, {integer}>>` in the current scope
--> <anon>:7:10
|
7 | .map(|(x, y)| x * y)
| ^^^
|
= note: the method `map` exists but the following trait bounds were not satisfied: `&std::slice::Iter<'_, {integer}> : std::iter::Iterator`, `std::iter::Zip<std::slice::Iter<'_, {integer}>, &std::slice::Iter<'_, {integer}>> : std::iter::Iterator`
But this does work:
fn main() {
let a = vec![1, 2, 3, 4];
let b = a.clone();
// slice and iter (correct way)
let s: i32 = a[1..a.len()].iter()
.zip(b[1..b.len()].iter())
.map(|(x, y)| x * y)
.sum();
println!("{}", s);
}
Please explain how vectors work in Rust and the difference above when I iter().
In short: you probably misunderstood operator precedence:
&b[1..b.len()].iter()
Is equal to:
&(b[1..b.len()].iter())
And since zip() is expecting something that implements IntoIterator, the call fails, since a reference to this iterator type does not implement said trait.
Full Explanation
Let's try to understand the error message! Of course, we will first just look at the first error:
error[E0277]: the trait bound `&std::slice::Iter<'_, {integer}>: std::iter::Iterator` is not satisfied
--> <anon>:6:10
|
6 | .zip(&b[1..b.len()].iter())
| ^^^ trait `&std::slice::Iter<'_, {integer}>: std::iter::Iterator` not satisfied
|
= note: `&std::slice::Iter<'_, {integer}>` is not an iterator; maybe try calling `.iter()` or a similar method
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&std::slice::Iter<'_, {integer}>`
Wow, that's quite a mouthful. But we can see that some trait bound requirement of the function zip() is violated. So, let's look at the signature of said function:
fn zip<U>(self, other: U) -> Zip<Self, U::IntoIter>
where U: IntoIterator
What matters is the other argument (type U). U has to be IntoIterator. This trait is implemented for quite a few types ... let's check what type we're trying to pass into zip():
&b[1..b.len()].iter()
To analyze this completely, we need to understand quite something, but I'll try to break it down. First, let's disambiguate operator precedence by inserting more parenthesis. The above code snippet is equivalent to:
&(b[1..b.len()].iter())
An expression foo[bar] desugares to *::std::ops::Index::index(&foo, bar). This is the most complex part here, but looking this up in the documentation reveals that the expression b[1..b.len()] has the type [i32].
On that type, you call iter() which returns a type Iter<_, _> which is the iterator type for slices.
Now the&: you borrow this Iter<_, _> thing, resulting in &Iter<_, _>.
And hey, this matches the error message! Look at the last note:
note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&std::slice::Iter<'_, {integer}>`
So... what does satisfy the IntoIterator trait? For one, every type that implements Iterator (e.g. Iter<_, _>) also implements IntoIterator. So you can just remove the & in the expression and it works!
But we can do even better! IntoIterator is also implemented for &[T], so you can also just remove the .iter() and it works!
Working Code
let s: i32 = a[1..].iter()
.zip(&b[1..])
.map(|(x, y)| x * y)
.sum();
Note: I also removed the ranges' upper bounds to make them half open, as Paolo Falabella suggested.
Your first version has an issue with operator precedence: &a[1..a.len()].iter() applies iter() first and then takes a reference to it, ending with a reference to a std::slice::Iter.
As you can see on the docs for Iter , there is an impl Iterator for Iter but not for &Iter.
This is what the first error is trying to say: (look at the part that says: &std::slice::Iter<'_, {integer}> is not an iterator).
Simplifying a bit, you can have:
fn main() {
let a = vec![1, 2, 3, 4];
// let b = a.clone(); // no more need to clone. We're going to only
// work with references
let s: i32 = (&a[1..]).iter() // you don't need the a.len()
// to slice to the end
.zip(&a[1..]) // &a implements IntoIter, which zip
// accepts, so you don't need iter()
.map(|(x, y)| x * y)
.sum();
println!("{}", s);
}
Iterator::zip expects something that implements IntoIterator.
Instead of passing an Iterator, you're passing a reference to the Iterator. Iterators mutate, and a reference isn't sufficient.
You can resolve this by using parenthesis to make it clear what you're trying to grab a reference from
fn main() {
let a = vec![1, 2, 3, 4];
let b = a.clone();
let s: i32 = (&a)[1..a.len()].iter()
.zip(((&b)[1..b.len()]).iter())
.map(|(x, y)| x * y)
.sum();
println!("{}", s);
}

Resources