splice method type mismatch - multithreading

So I have a vector of booleans hidden behind a Arc of a Mutex:
let mut vec: Arc<Mutex<Vec<bool>>> = Arc::new(Mutex::new(vec![false; size]));
I then spawn off multiple threads that do work on segments of another vector (of the same size). For example, suppose size=20. Then, thread 1 works on indices 0 - 4, thread 2 works on indices 5 - 9, and so on.
After each thread has done its work on the segment, I would like to put it back into this vec Arc/Mutex/Vector. I'm having a bit of trouble doing that. This is what I have tried so far:
let mut vec = next.lock().unwrap(); // Blocks until we can acquire
let mut data = *(& *vec); // Pulls the vector out (type std::vec::Vec<bool>)
data.splice(min..=max, segment.iter().clone()).collect(); // Tries to add our segment in
segment (seen in the last line) is a std::vec::Vec<bool> that was created in the thread.
Hopefully my intentions are clear.
However, I'm getting this error:
type mismatch resolving `<std::slice::Iter<'_, bool> as IntoIterator>::Item == bool`
data.splice(min..=max, segment.iter().clone()).collect();
^^^^^^ expected reference, found `bool`
note: expected reference `&bool`
found type `bool`
Any ideas?

You're accidentally cloning the iterator with .clone(). You probably meant to call .cloned() so the iterator clones its items.
data.splice(min..=max, segment.iter().cloned()).collect();

Related

Use of moved value

I have a simple function in Rust that iterates through numbers and adds them to a vector if they fulfill a condition. This condition is a function that uses a previously defined variable, prime_factors.
The is_multiperfect function only needs to look things up in the prime_factors variable.
fn get_all_mpn_below(integer: usize) -> Vec<usize> {
let prime_factors = get_prime_factors_below(integer);
let mut mpn = vec![1];
for n in (2..integer).step_by(2) {
if is_multiperfect(n, prime_factors) {
mpn.push(n);
}
}
return mpn;
}
However, this yields the following error:
use of moved value: `prime_factors`
let prime_factors = get_prime_factors_below(integer);
------------- move occurs because `prime_factors` has type `HashMap<usize, Vec<usize>>`, which does not implement the `Copy` trait
if is_multiperfect(n, prime_factors) {
^^^^^^^^^^^^^ value moved here, in previous iteration of loop
I've looked up the error and found it was about ownership, however I fail to understand how ownership applies here.
How can I fix this error?
as I don't declare another variable.
Why would you think that's relevant?
Moving is simply the default behaviour of Rust when transferring values (whether setting them, or passing them to function, or returning them from functions). This occurs for all types which are not Copy.
How can I fix this error?
Hard to say since the problem is is_multiperfect and you don't provide that code, so the reader, not being psychic, has no way to know what is_multiperfect wants out of prime_factors.
Possible solutions are:
clone() the map, this creates a complete copy which the callee can use however it wants, leaving the original available, this gives the callee complete freedom but incurs a large cost for the caller
pass the map as an &mut (unique / mutable reference), if the callee needs to update it
pass the map as an & (shared reference), if the callee just needs to look things up in the map

Immutable access in rust

I am new to rust from python and have used the functional style in python extensively.
What I am trying to do is to take in a string (slice) (or any iterable) and iterate with a reference to the current index and the next index. Here is my attempt:
fn main() {
// intentionally immutable, this should not change
let x = "this is a
multiline string
with more
then 3 lines.";
// initialize multiple (mutable) iterators over the slice
let mut lineiter = x.chars();
let mut afteriter = x.chars();
// to have some reason to do this
afteriter.skip(1);
// zip them together, comparing the current line with the next line
let mut zipped = lineiter.zip(afteriter);
for (char1, char2) in zipped {
println!("{:?} {:?}", char1, char2);
}
}
I think it should be possible to get different iterators that have different positions in the slice but are referring to the same parts of memory without having to copy the string, but the error I get is as follows:
error[E0382]: use of moved value: `afteriter`
--> /home/alex/Documents/projects/simple-game-solver/src/src.rs:15:35
|
10 | let afteriter = x.chars();
| --------- move occurs because `afteriter` has type `std::str::Chars<'_>`, which does not implement the `Copy` trait
11 | // to have some reason to do this
12 | afteriter.skip(1);
| --------- value moved here
...
15 | let mut zipped = lineiter.zip(afteriter);
| ^^^^^^^^^ value used here after move
I also get a warning telling me that zipped does not need to be mutable.
Is it possible to instantiate multiple iterators over a single variable and if so how can it be done?
Is it possible to instantiate multiple iterators over a single variable and if so how can it be done?
If you check the signature and documentation for Iterator::skip:
fn skip(self, n: usize) -> Skip<Self>
Creates an iterator that skips the first n elements.
After they have been consumed, the rest of the elements are yielded. Rather than overriding this method directly, instead override the nth method.
You can see that it takes self by value (consumes the input iterator) and returns a new iterator. This is not a method which consumes the first n elements of the iterator in-place, it's one which converts the existing iterator into one which skips the first n elements.
So instead of:
let mut afteriter = x.chars();
afteriter.skip(1);
you just write:
let mut afteriter = x.chars().skip(1);
I also get a warning telling me that zipped does not need to be mutable.
That's because Rust for loop uses the IntoIterator trait, which moves the iterable into the loop. It's not creating a mutable reference, it's just consuming whatever the RHS is.
Therefore it doesn't care what the mutability of the variable. You do need mut if you iterate explicitly, or if you call some other "terminal" method (e.g. nth or try_fold or all), or if you want to iterate on the mutable reference (that's mostly useful for collections though), but not to hand off iterators to some other combinator method, or to a for loop.
A for loop takes self, if you will. Just as for_each does in fact.
Thanks to #Stargateur for giving me the solution. The .skip(1) takes ownership of afteriter and returns ownership to a version without the first element. What was happening before was ownership was lost on the .skip and so the variable could not be mutated anymore (I am pretty sure)

Why does cloned() allow this function to compile

I'm starting to learn Rust and I tried to implement a function to reverse a vector of strings. I found a solution but I don't understand why it works.
This works:
fn reverse_strings(strings:Vec<&str>) -> Vec<&str> {
let actual: Vec<_> = strings.iter().cloned().rev().collect();
return actual;
}
But this doesn't.
fn reverse_strings(strings:Vec<&str>) -> Vec<&str> {
let actual: Vec<_> = strings.iter().rev().collect(); // without clone
return actual;
}
Error message
src/main.rs:28:10: 28:16 error: mismatched types:
expected `collections::vec::Vec<&str>`,
found `collections::vec::Vec<&&str>`
(expected str,
found &-ptr) [E0308]
Can someone explain to me why? What happens in the second function? Thanks!
So the call to .cloned() is essentially like doing .map(|i| i.clone()) in the same position (i.e. you can replace the former with the latter).
The thing is that when you call iter(), you're iterating/operating on references to the items being iterated. Notice that the vector already consists of 'references', specifically string slices.
So to zoom in a bit, let's replace cloned() with the equivalent map() that I mentioned above, for pedagogical purposes, since they are equivalent. This is what it actually looks like:
.map(|i: & &str| i.clone())
So notice that that's a reference to a reference (slice), because like I said, iter() operates on references to the items, not the items themselves. So since a single element in the vector being iterated is of type &str, then we're actually getting a reference to that, i.e. & &str. By calling clone() on each of these items, we go from a & &str to a &str, just like calling .clone() on a &i64 would result in an i64.
So to bring everything together, iter() iterates over references to the elements. So if you create a new vector from the collected items yielded by the iterator you construct (which you constructed by calling iter()) you would get a vector of references to references, that is:
let actual: Vec<& &str> = strings.iter().rev().collect();
So first of all realize that this is not the same as the type you're saying the function returns, Vec<&str>. More fundamentally, however, the lifetimes of these references would be local to the function, so even if you changed the return type to Vec<& &str> you would get a lifetime error.
Something else you could do, however, is to use the into_iter() method. This method actually does iterate over each element, not a reference to it. However, this means that the elements are moved from the original iterator/container. This is only possible in your situation because you're passing the vector by value, so you're allowed to move elements out of it.
fn reverse_strings(strings:Vec<&str>) -> Vec<&str> {
let actual: Vec<_> = strings.into_iter().rev().collect();
return actual;
}
playpen
This probably makes a bit more sense than cloning, since we are passed the vector by value, we're allowed to do anything with the elements, including moving them to a different location (in this case the new, reversed vector). And even if we don't, the vector will be dropped at the end of that function anyways, so we might as well. Cloning would be more appropriate if we're not allowed to do that (e.g. if we were passed the vector by reference, or a slice instead of a vector more likely).

Confusion with short lived lifetimed values that (on the surface) seem perfectly safe

I'm having an issue writing a Lexical Analyzer in Rust where certain functions are starting to complain about simple snippets that would otherwise appear harmless. This is starting to become an annoyance as the error messages are not helping me pinpoint the cause of my problems and so this is the second time I'm reaching out on the same program in the same week (previous question here).
I have read the book, I've understood everything I could from it. I've also watched/read numerous other articles and videos discussing lifetimes (both explicit and implicit) and for the most part the concept behind borrowing and moving make perfect sense, except in cases like the following:
My lexer has a next function who's purpose is to peek ahead at the next character and return it.
struct Lexer<'a> {
src: str::Chars<'a>,
buf: String,
// ... not important
}
impl<'a> Lexer<'a> {
// ... not relevant
// originally this -> Option<&char> which caused it's own slew of problems
// that I thought dereferencing the character would solve.
fn next(&self) -> Option<char> {
let res = self.src.peekable().peek();
// convert Option<&char> to Option<char>
match res {
Some(ref c) => Some(*c.clone()),
None => None
}
}
// ... not relevant
}
The error that I'm getting when doing this is:
error: borrowed value does not live long enough
let res = self.src.peekable().peek();
^~~~~~~~~~~~~~~~~~~
What I understand from this error is that the value from peekable() is not living long enough, which kind of makes sense to me. I'm only referencing the return in that line and calling another function which I imagine is returning a pointer to the character at the next location with the iterator. My naive solution to this was:
let mut peeker = self.src.peekable();
let res = peeker.peek();
If I implement this solution, I see a different error which also does not make sense to me:
error: cannot move out of borrowed content
let mut peeker = self.src.peekable();
^~~~
I'm not quite sure what's moving self out of a borrowed context here (I know it's borrowed from &self but not sure what's moving it out of the borrowed context.
EDIT
I proposed a question with details that were wildly inaccurate. The portion of the post that contained those details has been updated with actual facts - I mixed up two different situations where I had encountered a similar error (similar to me, at least).
Let's start with the second error.
As mentioned in the comments, Iterator::peekable is an iterator adapter that consumes the iterator it is going to make peekable. A small reproduction:
let values = [1,2,3];
let mut iterator = values.iter();
iterator.peekable(); // Consumes `iterator`
iterator.next(); // Not available anymore!
You can use Iterator::by_ref to get a reference that can then itself be consumed. Note that the underlying iterator will still be advanced!
let values = [1,2,3];
let mut iterator = values.iter();
iterator.by_ref().peekable();
iterator.next();
In your case, you are trying to consume the value out of a borrowed struct (via &self), which has the specific error cannot move out of borrowed content.
Let's look at your original error:
let values = [1,2,3];
let next = values.iter().peekable().peek();
The problem here is that peek returns a reference. This makes sense, as we don't know if the item we are iterating over is Copyable. However, that reference has to have somewhere to live. That place to live is the Peekable iterator itself! Peekable allocates enough space to store the "next" element. When you call peek, it advances the underlying iterator, stores the value, then returns the reference. Check out the function signature for peek to see this captured in code:
fn peek(&mut self) -> Option<&I::Item>
You can re-add the lifetimes to be explicit:
fn peek<'a>(&'a mut self) -> Option<&'a I::Item>
In the one-line version, you create and then destroy the Peekable, so there's nowhere for the value to live, so the reference dies in the same statement.

Why does the compiler tell me to consider using a `let` binding" when I already am?

What is my error and how to fix it?
fn get_m() -> Vec<i8> {
vec![1, 2, 3]
}
fn main() {
let mut vals = get_m().iter().peekable();
println!("Saw a {:?}", vals.peek());
}
(playground)
The compiler's error suggests "consider using a let binding" — but I already am:
error[E0597]: borrowed value does not live long enough
--> src/main.rs:6:45
|
6 | let mut vals = get_m().iter().peekable();
| ------- ^ temporary value dropped here while still borrowed
| |
| temporary value created here
7 | println!("Saw a {:?}", vals.peek());
8 | }
| - temporary value needs to live until here
|
= note: consider using a `let` binding to increase its lifetime
This is obviously a newbie question -- though I thought I'd written enough Rust at this point that I had a handle on the borrow checker... apparently I haven't.
This question is similar to Using a `let` binding to increase value lifetime, but doesn't involve breaking down an expression into multiple statements, so I don't think the problem is identical.
The problem is that the Peekable iterator lives to the end of the function, but it holds a reference to the vector returned by get_m, which only lasts as long as the statement containing that call.
There are actually a lot of things going on here, so let's take it step by step:
get_m allocates and returns a vector, of type Vec<i8>.
We make the call .iter(). Surprisingly, Vec<i8> has no iter method, nor does it implement any trait that has one. So there are three sub-steps here:
Any method call checks whether its self value implements the Deref trait, and applies it if necessary. Vec<i8> does implement Deref, so we implicitly call its deref method. However, deref takes its self argument by reference, which means that get_m() is now an rvalue appearing in an lvalue context. In this situation, Rust creates a temporary to hold the value, and passes a reference to that. (Keep an eye on this temporary!)
We call deref, yielding a slice of type &[i8] borrowing the vector's elements.
This slice implements the SliceExt trait, which does have an iter method. Finally! This iter also takes its self argument by reference, and returns a std::slice::Iter holding a reference to the slice.
We make the call .peekable(). As before, std::slice::Iter has no peekable method, but it does implement Iterator; IteratorExt is implemented for every Iterator; and IteratorExt does have a peekable method. This takes its self by value, so the Iter is consumed, and we get a std::iter::Peekable back in return, again holding a reference to the slice.
This Peekable is then bound to the variable vals, which lives to the end of the function.
The temporary holding the original Vec<i8>, to whose elements the Peekable refers, now dies. Oops. This is the borrowed value not living long enough.
But the temporary dies there only because that's the rule for temporaries. If we give it a name, then it lasts as long as its name is in scope:
let vec = get_m();
let mut peekable = vec.iter().peekable();
println!("Saw a {:?}", vals.peek());
I think that's the story. What still confuses me, though, is why that temporary doesn't live longer, even without a name. The Rust reference says, "A temporary's lifetime equals the largest lifetime of any reference that points to it." But that's clearly not the case here.
This is happening because you are trying to run your .iter().peekable() on the actual vector inside of get_m(), which is getting re-referenced by vals.
Basically, you want something like this:
fn get_m() -> Vec<i8> {
vec![1, 2, 3]
}
fn main() {
let vals = get_m();
let mut val = vals.iter().peekable();
println!("Saw a {:?}", val.peek());
}
(Playground)
Result:
Saw a Some(1)

Resources