Why is rust raising error '`()` is not an iterator'? [duplicate] - rust

This question already has an answer here:
How do I sort an array?
(1 answer)
Closed 6 days ago.
I tried to write a program that does the following thing: take all suffixes of a given string s, then sort these suffixes with dictionary order.
here is my code:
let mut sorted = (0..s.len())
.map(|i| (i, &s[i..s.len()]))
.collect::<Vec<(usize, &str)>>()
.sort_by_key(|k| k.1);
for elem in sorted {
println!("{} {}", elem.0, elem.1);
}
and rust compiler gives an error:
error[E0277]: `()` is not an iterator
--> src/lt05.rs:7:17
|
7 | for elem in sorted {
| ^^^^^^ `()` is not an iterator
|
= help: the trait `Iterator` is not implemented for `()`
= note: required for `()` to implement `IntoIterator`
Could anyone please explain what is wrong in this code?

Vec::sort_by_key sorts a vector in place and returns (). So in your code sorted ends up being assigned (), the unit type which you can't iterate over.
To fix this you can simply sort the vector after you've constructed it by moving the call to sort_by_key into a separate statement and then iterate over the sorted vector. See example below. Here is a Rust Playground which does this.
fn main() {
let s = "thisisatest";
let mut sorted =
(0..s.len())
.map(|i| (i, &s[i..s.len()]))
.collect::<Vec<(usize, &str)>>();
sorted.sort_by_key(|k| k.1);
for elem in sorted {
println!("{} {}", elem.0, elem.1);
}
}
Output
6 atest
8 est
1 hisisatest
4 isatest
2 isisatest
5 satest
3 sisatest
9 st
10 t
7 test
0 thisisatest

Related

How can I take a number of values from an iterator inside a for loop?

I have an infinite iterator and I want to print different slices from the iterator.
So, if I call extract(8,&[1,2,3,4]), in console i want to see/get:
1
2 3
4 1 2
3 4 1 2
3 4 1 2 3
4 1 2 3 4 1
2 3 4 1 2 3 4
My attemp:
fn extract(n: usize, seq: &[u16]) {
let mut iterator = seq.iter().cycle();
for it in 1..n {
iterator.take(it).for_each(|x| print!("{} ", x)); // <- Problem is here
print!("\n");
}
}
When I compile:
warning: variable does not need to be mutable
--> src/lib.rs:2:9
|
2 | let mut iterator = seq.iter().cycle();
| ----^^^^^^^^
| |
| help: remove this `mut`
|
= note: `#[warn(unused_mut)]` on by default
error[E0382]: use of moved value: `iterator`
--> src/lib.rs:5:9
|
2 | let mut iterator = seq.iter().cycle();
| ------------ move occurs because `iterator` has type `std::iter::Cycle<std::slice::Iter<'_, u16>>`, which does not implement the `Copy` trait
...
5 | iterator.take(it).for_each(|x| println!("{} ", x));
| ^^^^^^^^ value moved here, in previous iteration of loop
I understand that iterator changes its value in each loop iteration. That is why I marked as mutated var. But somehow, iterator var is used as argument of a function (which I can't see) and the iterator is moved. So in the next loop iteration, iterator var is out of scope and I get the moved value error.
To understand better my code:
Where is my iterator variable moving to?
How can I use the iterator inside the loop without this problem?
As others wrote, take consumes your iterator. To avoid this, you can use by_ref which wraps the original iterator and can be consumed without consuming the original iterator
fn extract(n: usize, seq: &[u16]) {
let mut iterator = seq.iter().cycle();
for it in 1..n {
iterator.by_ref().take(it).for_each(|x| println!("{} ", x));
print!("\n");
}
}
If you look at the exact error message:
error[E0382]: use of moved value: `iterator`
--> src/lib.rs:5:6
|
2 | let mut iterator = seq.iter().cycle();
| ------------ move occurs because `iterator` has type `std::iter::Cycle<std::slice::Iter<'_, u16>>`, which does not implement the `Copy` trait
...
5 | iterator.take(it).for_each(|x| println!("{} ", x)); // <- Problem is here
| ^^^^^^^^ value moved here, in previous iteration of loop
The compiler underlines where the value is moved, which is in iterator.take(…). Let's have a look at Iterator::take's definition:
fn take(self, n: usize) -> Take<Self>
It takes self by value, that is, to call it, you have to move the instance.

Vectors borrowing and ownership [duplicate]

This question already has answers here:
What does it mean to pass in a vector into a `for` loop versus a reference to a vector?
(1 answer)
How can I solve "use of moved value" and "which does not implement the `Copy` trait"?
(1 answer)
What do I have to do to solve a "use of moved value" error?
(3 answers)
What does "cannot move out of index of" mean?
(2 answers)
Closed 2 years ago.
This doesn't work:
let vectors = vec![1, 2, 3, 4, 5, 6, 7];
for i in vectors {
println!("Element is {}", i);
}
let largest = vectors[0];
Error message:
error[E0382]: borrow of moved value: `vectors`
--> src/main.rs:8:19
|
2 | let vectors = vec![1, 2, 3, 4, 5, 6, 7];
| ------- move occurs because `vectors` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
3 |
4 | for i in vectors {
| -------
| |
| value moved here
| help: consider borrowing to avoid moving into the for loop: `&vectors`
...
8 | let largest = vectors[0];
| ^^^^^^^ value borrowed here after move
The vector has been moved into the loop. Its ownership — and that of its individual elements — has been transferred there permanently.
But this works:
let largest = vectors[0];
let largest2 = vectors[0];
I don't know why; the vectors[0] value should have been moved to largest and largest2 should then fail, but it didn't.
When you use vectors inside a for..in loop, Rust will call the IntoIterator::into_iter trait method of the Vec, which takes ownership of self. Therefore you cannot use vectors afterwards.
use std::iter::IntoIterator;
// these are equivalent
for i in vectors { /* ... */ }
for i in IntoIterator::into_iter(vectors) { /* ... */ }
The index operator, on the other hands, calls the Index::index trait method of the Vec, which takes self by reference. Additionally, it automatically dereferences the value, so that if the items inside the vector implement Copy, they will be copied out of the vector instead of borrowed (you need to explicitly borrow if you want a reference):
use std::ops::Index;
// these are equivalent
let x = vectors[0];
let x = *Index::index(&vectors, 0);
// these are equivalent
let x = &vectors[0];
let x = Index::index(&vectors, 0);
The type of the values (probably i32) in your Vec implement the Copy trait, which means that they do not get moved out when indexing the vector, they get copied instead.
A Vec of such Copy types still doesn't implement Copy itself, so it gets moved into the loop. You can avoid this e.g. by writing
for i in vectors.iter() {
println!("Element is {}", *i);
}
The dereference (*) gives you an owned value like you'd get in your original code sample. It isn't necessary for println!, but might be necessary for other uses.

"cannot borrow as mutable because it is also borrowed as immutable" with match [duplicate]

This question already has answers here:
How to lookup from and insert into a HashMap efficiently?
(2 answers)
Closed 3 years ago.
I'm attempting to count the character frequency in a string and store the count of each character in a BTreeMap. However, I'm getting a warning and would like to get rid of it.
This is what I've tried:
use std::collections::BTreeMap;
fn letter_frequency(input: &str) -> BTreeMap<char, i32> {
let mut tree: BTreeMap<char, i32> = BTreeMap::new();
for item in &input.chars().collect::<Vec<char>>() {
match tree.get(item) {
Some(count) => tree.insert(*item, *count + 1),
None => tree.insert(*item, 1)
};
}
tree
}
This is the warning:
warning: cannot borrow `tree` as mutable because it is also borrowed as immutable
--> src/lib.rs:7:28
|
6 | match tree.get(item) {
| ---- immutable borrow occurs here
7 | Some(count) => tree.insert(*item, *count + 1),
| ^^^^ ------ immutable borrow later used here
| |
| mutable borrow occurs here
|
= note: #[warn(mutable_borrow_reservation_conflict)] on by default
= warning: this borrowing pattern was not meant to be accepted, and may become a hard error in the future
= note: for more information, see issue #59159 <https://github.com/rust-lang/rust/issues/59159>
How do I correctly use match with a BTreeMap to avoid the error ?
Like Svetlin mentions in a comment, the entry API is your friend. Below I've also removed one unneeded collect.
fn letter_frequency(input: &str) -> BTreeMap<char, i32> {
let mut tree = BTreeMap::new();
for item in input.chars() {
let count = tree.entry(item).or_insert(0);
*count += 1;
}
tree
}
The temporary variable count is not really needed: *tree.entry(item).or_insert(0) += 1; works just fine but might look a bit crowded at first.

How to match against Some(&T)? [duplicate]

This question already has answers here:
What is the difference between `e1` and `&e2` when used as the for-loop variable?
(1 answer)
Why is `ref` used instead of an asterisk in pattern matching?
(2 answers)
Closed 2 years ago.
The following code won't compile:
#[derive(Debug)]
struct Foo {
x: i32,
}
pub fn main() {
let a = vec![Foo { x: 1 }, Foo { x: 2 }];
match a.get(0) {
Some(&x) => println!("ref {:?}", x),
None => {}
}
}
Throws this error:
error[E0507]: cannot move out of a shared reference
--> src/main.rs:8:11
|
8 | match a.get(0) {
| ^^^^^^^^
9 | Some(&x) => println!("ref {:?}", x),
| -
| |
| data moved here
| move occurs because `x` has type `Foo`, which does not implement the `Copy` trait
I thought std::Vec<T>::get returns Some(&T) on success. Doesn't that mean an ampersand should be used in pattern matching?
I thought std::Vec<T>::get returns Some(&T) on success
Yes, you get an Option over a reference. Said otherwise, x, in Some(x) is a reference over the Foo instance.
But you do want a reference: the only way to print the element without removing it from the vector is to pass a reference to println, not the element itself. That's why
Some(x) => println!("ref {:?}", x),
is the right way.
When you do
Some(&x) => println!("ref {:?}", x),
on the other way, as &x is the reference over the Foo instance, x is the Foo instance, and thus you'd be moving it out of the vector when matching, which you can't do with a shared reference you got with get (and something you certainly don't want to do anyway).

Get first element from HashMap

I have a HashMap and need to get the first element:
type VarIdx = std::collections::HashMap<u16, u8>;
fn get_first_elem(idx: VarIdx) -> u16 {
let it = idx.iter();
let ret = match it.next() {
Some(x) => x,
None => -1,
};
ret
}
fn main() {}
but the code doesn't compile:
error[E0308]: match arms have incompatible types
--> src/main.rs:5:15
|
5 | let ret = match it.next() {
| _______________^
6 | | Some(x) => x,
7 | | None => -1,
8 | | };
| |_____^ expected tuple, found integral variable
|
= note: expected type `(&u16, &u8)`
found type `{integer}`
note: match arm with an incompatible type
--> src/main.rs:7:17
|
7 | None => -1,
| ^^
how can I fix it?
There is no such thing as the "first" item in a HashMap. There are no guarantees about the order in which the values are stored nor the order in which you will iterate over them.
If order is important then perhaps you can switch to a BTreeMap, which preserves order based on the keys.
If you just need to get the first value that you come across, in other words any value, you can do something similar to your original code: create an iterator, just taking the first value:
fn get_first_elem(idx: VarIdx) -> i16 {
match idx.values().next() {
Some(&x) => x as i16,
None => -1,
}
}
The method values() creates an iterator over just the values. The reason for your error is that iter() will create an iterator over pairs of keys and values which is why you got the error "expected tuple".
To make it compile, I had to change a couple of other things: -1 is not a valid u16 value so that had to become i16, and your values are u8 so had to be cast to i16.
As another general commentary, returning -1 to indicate failure is not very "Rusty". This is what Option is for and, given that next() already returns an Option, this is very easy to accomplish:
fn get_first_elem(idx: VarIdx) -> Option<u8> {
idx.values().copied().next()
}
The .copied() is needed in order to convert the &u8 values of the iterator into u8.
HashMap::iter returns an iterator over (&Key, &Value) pairs. What you want is HashMap::values, which produces an iterator that only produces the values of the HashMap.
Note that the order of the values is random. It has nothing to do with the order you put the values in or with the actual value of the values.

Resources