How I can iterate over borrowed array? - reference

I thought that it should be something like this, but I cannot iterate over an borrowed array.
fn print_me<'a, I>(iter: &'a I) where I: Iterator<Item = i32> {
for i in *iter {
println!("{}", i);
}
}
fn main() {
let numbers = vec![1, 2, 3];
//let numbers = &numbers;
print_me(numbers.iter());
}
But Rust complains:
<anon>:15:12: 15:26 error: mismatched types:
expected `&_`,
found `core::slice::Iter<'_, _>`
(expected &-ptr,
found struct `core::slice::Iter`) [E0308]
<anon>:15 print_me(numbers.iter());
^~~~~~~~~~~~~~

An iterator is a regular object; you work with an iterator directly, not typically through references—and certainly not typically through immutable references, for taking the next value of an iterator takes &mut self. And a reference to an iterator is quite different from an iterator over references.
Fixing this part, you then have this:
fn print_me<I: Iterator<Item = i32>>(iter: I) {
for i in iter {
println!("{}", i);
}
}
This doesn’t fix everything, however, because [T].iter() produces a type implementing Iterator<Item = &T>—it iterates over references to each item. The most common fix for that is cloning each value with the handy .cloned() method, which is equivalent to .map(|x| x.clone()).
Here, then, is the rest of what you end up with:
fn main() {
let numbers = vec![1, 2, 3];
print_me(numbers.iter().cloned());
}

Related

Why does an Iterator trait object referring to a sibling field fail to compile when the concrete type works?

I'd like to have an iterator that points into a Vec of the same struct.
The following works fine (playground):
struct Holder1<'a> {
vec: Vec<i32>,
iterator: Option<Box<std::slice::Iter<'a, i32>>>,
}
fn holder1_test() {
let vec = vec![1, 2, 3, 4];
let mut holder = Holder1 {
vec,
iterator: None,
};
let iterator: Box<std::slice::Iter<'_, i32>> = Box::new(holder.vec.iter());
holder.iterator = Some(iterator);
for iter_elem in holder.iterator.as_mut().unwrap() {
println!("iter: {}", iter_elem);
}
}
(I know the Box isn't needed here, I just wanted to keep this as close as possible to the next code snippet.)
I'd like to use a trait object, dyn Iterator, instead of the concrete type. I've slightly modified the example from above for that (playground):
struct Holder2<'a> {
vec: Vec<i32>,
iterator: Option<Box<dyn Iterator<Item = &'a i32>>>,
}
fn holder2_test() {
let vec = vec![1, 2, 3, 4];
let mut holder = Holder2 {
vec,
iterator: None,
};
let iterator: Box<dyn Iterator<Item = &'_ i32>> = Box::new(holder.vec.iter());
holder.iterator = Some(iterator);
for iter_elem in holder.iterator.as_mut().unwrap() {
println!("iter: {}", iter_elem);
}
}
This fails to compile:
error[E0597]: `holder.vec` does not live long enough
--> src/lib.rs:12:64
|
12 | let iterator: Box<dyn Iterator<Item = &'_ i32>> = Box::new(holder.vec.iter());
| ^^^^^^^^^^ borrowed value does not live long enough
...
18 | }
| -
| |
| `holder.vec` dropped here while still borrowed
| borrow might be used here, when `holder` is dropped and runs the destructor for type `Holder2<'_>`
What makes the second example so different to the first example that causes the compilation failure? Both iterators point to an element in the Vec of the same struct - so what's the conceptual difference here? Is there a way to get this to work with trait objects?
I'm aware that using an index instead of an iterator would solve this, but I'm rather interested in the underlying reasons of why this doesn't work.

How can I construct and pass an iterator of iterators?

I am trying to grok Rust by implementing simple algorithms in it. I managed to make a generic merge_sorted, which ended up having the following signature:
fn merge_sorted<IL, ILL, I: Ord>(mut arrays: ILL) -> Vec<I>
where
IL: Iterator<Item = I>,
ILL: Iterator<Item = IL>,
{
// ...
}
This seems to be compiling on its own. The signature makes sense to me, as the function consumes the top-level iterator, and all the iterators it returns too. However, I am unable to construct a valid value to pass to this function:
fn main() {
let v1 = vec![1, 2];
let vectors = vec![v1.iter()];
merge_sorted(vectors.iter());
}
As expected, vectors in this sample has the type:
std::vec::Vec<std::slice::Iter<'_, i32>>
This is the error message I get:
error[E0277]: the trait bound `&std::slice::Iter<'_, {integer}>: std::iter::Iterator` is not satisfied
--> src\main.rs:58:5
|
58 | merge_sorted(vectors.iter());
| ^^^^^^^^^^^^ `&std::slice::Iter<'_, {integer}>` is not an iterator; maybe try calling `.iter()` or a similar method
|
= help: the trait `std::iter::Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>`
note: required by `merge_sorted`
Where does the & come from?
Vec::iter borrows the items it contains, so you are iterating over borrowed iterators (&std::slice::Iter) that do not implement Iterator. To consume a vector in order to have the ownership of the items, you must call Vec::into_iter:
fn main() {
let v1 = vec![1, 2];
let vectors = vec![v1.iter()]; // You can use `into_iter` there to iterate over ints.
merge_sorted(vectors.into_iter());
}
You can also require IntoIterators that can make easier the usage of your API:
fn merge_sorted<IterT, IterIterT, T: Ord>(mut arrays: IterIterT) -> Vec<T>
where
IterT: IntoIterator<Item = T>,
IterIterT: IntoIterator<Item = IterT>,
{
panic!();
}
fn main() {
let v1 = vec![1, 2];
let vectors = vec![v1];
merge_sorted(vectors);
}

How can I borrow from a HashMap to read and write at the same time?

I have a function f that accepts two references, one mut and one not mut. I have values for f inside a HashMap:
use std::collections::HashMap;
fn f(a: &i32, b: &mut i32) {}
fn main() {
let mut map = HashMap::new();
map.insert("1", 1);
map.insert("2", 2);
{
let a: &i32 = map.get("1").unwrap();
println!("a: {}", a);
let b: &mut i32 = map.get_mut("2").unwrap();
println!("b: {}", b);
*b = 5;
}
println!("Results: {:?}", map)
}
This doesn't work because HashMap::get and HashMap::get_mut attempt to mutably borrow and immutably borrow at the same time:
error[E0502]: cannot borrow `map` as mutable because it is also borrowed as immutable
--> src/main.rs:15:27
|
12 | let a: &i32 = map.get("1").unwrap();
| --- immutable borrow occurs here
...
15 | let b: &mut i32 = map.get_mut("2").unwrap();
| ^^^ mutable borrow occurs here
...
18 | }
| - immutable borrow ends here
In my real code I'm using a large, complex structure instead of a i32 so it is not a good idea to clone it.
In fact, I'm borrowing two different things mutably/immutably, like:
struct HashMap {
a: i32,
b: i32,
}
let mut map = HashMap { a: 1, b: 2 };
let a = &map.a;
let b = &mut map.b;
Is there any way to explain to the compiler that this is actually safe code?
I see how it possible to solve in the concrete case with iter_mut:
{
let mut a: &i32 = unsafe { mem::uninitialized() };
let mut b: &mut i32 = unsafe { mem::uninitialized() };
for (k, mut v) in &mut map {
match *k {
"1" => {
a = v;
}
"2" => {
b = v;
}
_ => {}
}
}
f(a, b);
}
But this is slow in comparison with HashMap::get/get_mut
TL;DR: You will need to change the type of HashMap
When using a method, the compiler does not inspect the interior of a method, or perform any runtime simulation: it only bases its ownership/borrow-checking analysis on the signature of the method.
In your case, this means that:
using get will borrow the entire HashMap for as long as the reference lives,
using get_mut will mutably borrow the entire HashMap for as long as the reference lives.
And therefore, it is not possible with a HashMap<K, V> to obtain both a &V and &mut V at the same time.
The work-around, therefore, is to avoid the need for a &mut V entirely.
This can be accomplished by using Cell or RefCell:
Turn your HashMap into HashMap<K, RefCell<V>>,
Use get in both cases,
Use borrow() to get a reference and borrow_mut() to get a mutable reference.
use std::{cell::RefCell, collections::HashMap};
fn main() {
let mut map = HashMap::new();
map.insert("1", RefCell::new(1));
map.insert("2", RefCell::new(2));
{
let a = map.get("1").unwrap();
println!("a: {}", a.borrow());
let b = map.get("2").unwrap();
println!("b: {}", b.borrow());
*b.borrow_mut() = 5;
}
println!("Results: {:?}", map);
}
This will add a runtime check each time you call borrow() or borrow_mut(), and will panic if you ever attempt to use them incorrectly (if the two keys are equal, unlike your expectations).
As for using fields: this works because the compiler can reason about borrowing status on a per-field basis.
Something appears to have changed since the question was asked. In Rust 1.38.0 (possibly earlier), the following compiles and works:
use std::collections::HashMap;
fn f(a: &i32, b: &mut i32) {}
fn main() {
let mut map = HashMap::new();
map.insert("1", 1);
map.insert("2", 2);
let a: &i32 = map.get("1").unwrap();
println!("a: {}", a);
let b: &mut i32 = map.get_mut("2").unwrap();
println!("b: {}", b);
*b = 5;
println!("Results: {:?}", map)
}
playground
There is no need for RefCell, nor is there even a need for the inner scope.

Does &mut do anything when declaring a for loop variable?

Consider the following (dumb) program:
fn main() {
let mut array = &mut [1u8, 2u8, 3u8];
for &mut value in array {
}
}
It compiles and runs okay (though warns about unused variables/unnecessary mutability, as expected). But what does &mut do in the for statement?
It doesn't seem to give you a mutable reference into the array, since trying to assign value = 0; results in the error:
error[E0384]: re-assignment of immutable variable `value`
Is &mut here a no-op then?
So there's a few different things that's going on here. First, here's the answer:
fn main() {
let mut array = [1u8, 2u8, 3u8];
for value in &mut array {
*value = 0;
}
}
So. Where did you go wrong? Let's look at what value is, like this:
for &mut value in array {
let () = value;
}
This gives this error:
= note: expected type `u8`
= note: found type `()`
So here, value is a u8. But why? Well, let's try this one:
for value in array {
let () = value;
}
This gives:
= note: expected type `&mut u8`
= note: found type `()`
So, value here is an &mut u8, a reference into the array. So by saying for &mut value, we're saying "hey, this is going to be a mutable pointer to a u8. We'd like value to be the u8 value that's pointed at. This is because &mut value is a pattern, which binds against a &mut T and binds value to the T.
So, we remove the &mut, since we don't want a copy of the value, we want to use it to modify what's pointed to. So that looks like this:
fn main() {
let mut array = &mut [1u8, 2u8, 3u8];
for value in array {
*value = 0;
}
}
This... compiles! Are we done? Well, let's try to print out array, just to be sure:
fn main() {
let mut array = &mut [1u8, 2u8, 3u8];
for value in array {
*value = 0;
}
println!("{:?}", array);
}
This fails to compile:
error[E0382]: use of moved value: `array`
--> <anon>:7:22
|
3 | for value in array {
| ----- value moved here
We've destroyed array by iterating. Why's that? Well, when you loop over an array like this, you're saying you want to loop by owner. But that's not actually what we want; we want to loop by mutable reference.
Arrays have a method to help with this:
fn main() {
let mut array = &mut [1u8, 2u8, 3u8];
for value in array.iter_mut() {
*value = 0;
}
println!("{:?}", array);
}
iter_mut will iterate by &mut T rather than by T. So this works!
One last thing, though:
let mut array = &mut [1u8, 2u8, 3u8];
This says that array is a &mut [u8; 3], that is, a mutable reference to an array, not an array itself. This probably isn't what you actually want, and it's not neccesary with our code. So we can remove the &mut bit:
let mut array = [1u8, 2u8, 3u8];
And now you're at our first code sample.
Hope this helps!
Is &mut here a no-op then?
No, it's part of a pattern. Print the type of value:
fn main() {
let mut array = &mut [1u8, 2u8, 3u8];
for &mut value in array {
let () = value;
// expected type `u8`
}
for value in array {
let () = value;
// expected type `&mut u8`
}
}

How can I swap items in a vector, slice, or array in Rust?

My code looks like this:
fn swap<T>(mut collection: Vec<T>, a: usize, b: usize) {
let temp = collection[a];
collection[a] = collection[b];
collection[b] = temp;
}
Rust is pretty sure I'm not allowed to "move out of dereference" or "move out of indexed content", whatever that is. How do I convince Rust that this is possible?
There is a swap method defined for &mut [T]. Since a Vec<T> can be mutably dereferenced as a &mut [T], this method can be called directly:
fn main() {
let mut numbers = vec![1, 2, 3];
println!("before = {:?}", numbers);
numbers.swap(0, 2);
println!("after = {:?}", numbers);
}
To implement this yourself, you have to write some unsafe code. Vec::swap is implemented like this:
fn swap(&mut self, a: usize, b: usize) {
unsafe {
// Can't take two mutable loans from one vector, so instead just cast
// them to their raw pointers to do the swap
let pa: *mut T = &mut self[a];
let pb: *mut T = &mut self[b];
ptr::swap(pa, pb);
}
}
It takes two raw pointers from the vector and uses ptr::swap to swap them safely.
There is also a mem::swap(&mut T, &mut T) when you need to swap two distinct variables. That cannot be used here because Rust won't allow taking two mutable borrows from the same vector.
As mentioned by #gsingh2011, the accepted answer is no longer good approach. With current Rust this code works fine:
fn main() {
let mut numbers = vec![1, 2, 3];
println!("before = {:?}", numbers);
numbers.swap(0, 2);
println!("after = {:?}", numbers);
}
try it here

Resources