How properly use Iterator::chain in rust - 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.

Related

Rust ndarray slicing

I am using ndarray and trying to slice some arrays. This works
let y = arr2(&[[ 6, 5, 4],
[12, 11, 10]]);
let ip = y.slice(s![0, ..]);
println!("IP {}", ip);
but this
let y = arr2(&[[ 6, 5, 4],
[12, 11, 10]]);
let ip = y.slice(s![0, ..]);
println!("IP {}", ip[0]);
does not compile. What is going on?
Compile errors are:
Error[E0277]: the trait bound `i32: Dimension` is not satisfied
....
println!("IP {}", ip[0]);
| ^^^^^ the trait `Dimension` is not implemented for `i32`
| = note: required because of the requirements on the impl of `std::ops::Index<i32>` for `ArrayBase<ViewRepr<&i32>, i32>`
with other errors
error[E0308]: mismatched types
....
| let ip = y.slice(s![0, ..]);
| ^^^^^^^^^^^^^^^^^^ expected `i32`, found struct `Dim`
|
= note: expected type `i32`
found struct `Dim<[usize; 1]>`
The issue is that integer literals are by default i32, and so ip[0] tells Rust that ip: Index<i32>, which then fixes the type of slice's argument to be i32, but the type is supposed to be impl Dimension. (I don't fully understand the type hierarchy of ndarray's indices/dimensions, but this is close enough to be useful.) To work around this, simple replace ip[0] with ip[0_usize].

Cannot infer type for type parameter `S` when using HashSet::from_iter

I am trying to solve an online challenge that involves comparing two sets. I followed this answer to convert my Vec<i32> output to HashSet
use std::collections::HashSet;
use std::iter::FromIterator;
struct Solution {}
impl Solution {
pub fn solve(nums: Vec<i32>, k: i32) -> Vec<i32> {
// todo, return dummy for now
return vec![1, 2];
}
}
fn main() {
assert_eq!(
HashSet::from_iter(Solution::solve(vec![1, 2, 3], 2)),
HashSet::from_iter(vec![1i32, 2i32])
)
}
For reasons I don't understand yet, the compilation fails:
error[E0282]: type annotations needed
--> src/main.rs:15:9
|
15 | HashSet::from_iter(Solution::solve(vec![1, 2, 3], 2)),
| ^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `S` declared on the struct `HashSet`
It works fine for HashSet::from_iter(vec![1i32, 2i32])
I tried adding a type annotation like HashSet::from_iter::<Vec<i32>> with no avail. I also read the source implementation but still can't figure out what makes the compiler complain.
I can work around it by declaring it explicitly or construct the HashSet with a for loop and inserts, but I would like to understand what is going on here.
I'm using Rust 1.43.1.
I believe the answer from Kitsu is subtly incorrect since it suggests that Rust cannot infer the type of T because here may be an iterator implemented for a type P that collects a different type T (more on this at the end).
What's really happening
In fact, type inference for type S in HashSet<T, S> has nothing to do with the type of T. The issue is that there is no information in your program that allows the compiler to infer the type of S.
It is correct that adding a type parameter is sufficient to resolve the ambiguity:
HashSet::<i32>::from_iter(vec![1, 2, 3]);
This has nothing to do with the actual type you specify. Indeed, this works as well:
HashSet::<_>::from_iter(vec![1, 2, 3]);
The reason is that the definition of HashSet in the standard library includes a default type for S:
pub struct HashSet<T, S = RandomState> {
base: base::HashSet<T, S>,
}
By writing HashSet::<_>::from_iter(vec![1, 2, 3]); you're telling the compiler that it should use the default type for S, which is RandomState.
What about multiple implementations?
Kitsu's answer states that type inference fails for S because there might be multiple implementations of FromIterator. This is incorrect, but having multiple implementations can cause type inference to fail for T.
Consider this example:
fn iterator_demo() {
use std::collections::HashSet;
use std::hash::{BuildHasher, Hash};
use std::iter::FromIterator;
struct Empty;
impl<T, S> FromIterator<Empty> for HashSet<T, S>
where
T: Eq + Hash,
S: BuildHasher + Default,
{
fn from_iter<I>(iter: I) -> HashSet<T, S>
where
I: IntoIterator<Item = Empty>,
{
iter.into_iter().for_each(drop);
HashSet::default()
}
}
let x = HashSet::<_>::from_iter(vec![Empty, Empty]);
}
This causes type inference to fail; note that this is a failure to infer T, not S:
error[E0282]: type annotations needed for `HashSet<T>`
--> src/lib.rs:22:13
|
22 | let x = HashSet::<_>::from_iter(vec![Empty, Empty]);
| - ^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
| |
| consider giving `x` the explicit type `HashSet<T>`, with the type parameters specified
Specifying the type resolves this ambiguity:
let x = HashSet::<String>::from_iter(vec![Empty, Empty]);
Credit to matt1992 on the Rust Discord for helping me to understand what's really happening here.
Let's look at the FromIterator::from_iter declaration, you've been using:
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = A>,
After specifying HashSet compiler can deduce that Self is HashSet<S> for some S. T for your particular case can be deduced as a Vec<i32>: IntoIterator<Item = i32> (for the second line that is resolved after you explicitly specified an integer type).
But still, S is not deduced because, in general, you may have an implementation that collects HashSet<u64> from IntoIterator<Item = u8>. So compiler cannot understand what are items of the collected type. Then if you swap the expressions of the assert_eq error source changes:
assert_eq!(
HashSet::from_iter(vec![1i32, 2i32]),
/*
|
15 | HashSet::from_iter(vec![1i32, 2i32]),
| ^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `S` declared on the struct `HashSet`
*/
HashSet::from_iter(Solution::solve(vec![1, 2, 3], 2)),
)
The solution is fairly straightforward: you need to specify the item type of your HashSet:
assert_eq!(
HashSet::<i32>::from_iter(Solution::solve(vec![1, 2, 3], 2)),
HashSet::from_iter(vec![1i32, 2])
)

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