How to fold vector of vector in rust? - rust

I have a vector of vector like the following.
let m: Vec<Vec<u64>> = vec![
vec![1, 2, 3, 4, 5],
vec![1, 2, 3, 4, 5],
vec![1, 2, 3, 4, 5],
vec![1, 2, 3, 4, 5],
vec![1, 2, 3, 4, 5]
];
And add function that is intended add each element of two vector.
fn add(xs: &Vec<u64>, ys: &Vec<u64>) -> Vec<u64> {
xs.iter().zip(ys.iter()).map(|(x, y)| x + y).collect()
}
Now, I want to fold the vector of vector m.
What I tried is:
let s: Vec<u64> = m[1..]
.iter()
.fold(m[0], |acc, xs| add(&acc, xs));
But this code doesn't pass the compiler.
|
16 | .fold(m[0], |acc, xs| add(&acc, xs));
| ^^^^ move occurs because value has type `Vec<u64>`, which does not implement the `Copy` trait
I tried prepend & but the compiler still rejects:
|
16 | .fold(&m[0], |acc, xs| add(&acc, xs));
| ^^^^^ expected struct `Vec`, found `&Vec<u64>`
|
= note: expected struct `Vec<u64>`
found reference `&Vec<u64>`
help: consider removing the borrow
|
16 - .fold(&m[0], |acc, xs| add(&acc, xs));
16 + .fold(m[0], |acc, xs| add(&acc, xs));
|
I think the signature of add function is correct as it doesn't want to take ownership of the arguments vectors, and it returns a new vector so the ownership should be passed to the caller.
Actually, I tried every possible combinations (add/remove & from the function, etc.), but couldn't make the code pass the compiler.
Can you let me know what I missed, what is wrong with the above code? Thanks.

The first argument of fold must be the same type as its output. Therefore your suggestion of passing & m[0], which has type & Vec<u64>, won't work, since you want the fold to return Vec<u64> (notice value vs borrowed value). And using m[0] (without borrowing) won't work because you would be trying to move from a vector that is later used (in the iteration itself).
One option could be to start with m[0].clone() as the initial value. That does involve a cloning, obviously, but you need to allocate your output somehow anyway, so you can't do better. This works:
let s: Vec<u64> = m[1..].iter().fold(m[0].clone(), |acc, xs| add(& acc, xs));
Unrelatedly: I suggest you change add to have the more general signature fn add(xs: & [u64], ys: & [u64]) -> Vec<u64>. You can still use it the way you are (because & Vec<u64> coerces into & [u64]), but it's more general, because other types coerce into & [u64] too.

Use something like
let first = m.pop().unwrap();
let s: Vec<u64> = m
.iter()
.fold(first, |acc, xs| add(&acc, xs));
this avoids cloning the first argument. It assumes that the order of the operation does not matter.

Related

How to apply reduce to chunks (coming from a borrowed reference to an array)?

How can I make use of functional patterns without incurring in borrowing problems? The solution proposed by the compiler leads to another error (expected array [u8; 3], found '&[u8]') and it goes on from one error to another different error, indefinitely.
Some related code seem overly complicated for such a simple task like in this other question.
use reduce::Reduce;
/// Take an array representing a sequence of 3-tuples and fold it through an arbitrary sandwich logic.
fn sandwich(lst: &[u8])->[u8; 3]{
lst.chunks(3).reduce(|x, y| [x[0], y[1], x[0]]).unwrap()
}
/*
3 | lst.chunks(3).reduce(|x, y| [x[0], y[1], x[0]]).unwrap()
| ^^^^^^^^^^^^^^^^^^
| |
| expected `&[u8]`, found array `[u8; 3]`
| help: consider borrowing here: `&[x[0], y[1], x[0]]`
*/
The best compilable code I could write was this convoluted one, giving up reduce at all:
fn sandwich2(lst: &[u8])->[u8; 3]{
let mut r: [u8; 3] = lst[..].try_into().unwrap();
for i in (3..lst.len()).step_by(3) {
let y = &lst[i..i + 3];
r = [r[0], y[1], r[0]];
}
r
}
Please note that sandwich is just an example to illustrate the problem (that does nothing actually smart). I expect an external much more complex function instead of that lambda.
You have to somehow take ownership of the values into a required [u8; 3].
Maybe as this example using the iterator_fold_self feature (as per today nightly):
#![feature(iterator_fold_self)]
/// Take an array representing a sequence of 3-tuples and reduce it through an arbitrary sandwich logic.
fn sandwich(lst: &[u8]) -> [u8; 3] {
lst.chunks(3)
.map(|x| [x[0], x[1], x[2]])
.reduce(|x, y| [x[0], y[1], x[0]])
.unwrap()
}
fn main() {
let test_set = [1, 2, 3, 1, 2, 3];
println!("{:?}", sandwich(&test_set));
}
Playground
You can use try_into(from this famous answer) to get an owned slice:
fn sandwich(lst: &[u8]) -> [u8; 3] {
lst.chunks(3)
.map(|x| -> [u8; 3] { x.try_into().unwrap() } )
.reduce(|x, y| [x[0], y[1], x[0]])
.unwrap()
}
Playground

Rust: error[E0495]: cannot infer an appropriate lifetime for autorefdue to conflicting requirements in closure

Raw idea
In a dummy project I have, I would like to use cycling iterators (to generate integers for example).
use std::iter::Cycle;
type IntegerCycle = Cycle<std::slice::Iter<'static, i32>>;
fn generate_cycles() -> [IntegerCycle; 2] {
let mut cycles = [
[1, 2].iter().cycle(),
[2, 4].iter().cycle(),
];
cycles
}
fn main() {
let mut cycles = generate_cycles();
// ...
}
Refactor
Although the previous piece of code works as intended, my real world example is a bit more complicated, so I am looking to adapt the generate_cycles function to be able to perform more operations (in the following example, multiply by 2, then generate the cycling iterators).
For this, I tried to use arraymap:
extern crate arraymap;
use arraymap::ArrayMap;
use std::iter::Cycle;
type IntegerCycle = Cycle<std::slice::Iter<'static, i32>>;
fn generate_cycles() -> [IntegerCycle; 2] {
let mut cycles = [
[1, 2],
[2, 4],
];
cycles
.map(|points| {
points.map(|point| point*2)
})
.map(|points| {
points.iter().cycle()
})
}
fn main() {
let mut cycles = generate_cycles();
// ...
}
The problem
The above solution does not work, and, as a Rust beginner recently exposed to the concept of "lifetime", I do not understand why the compiler is complaining here, or what I can do to make him happy.
error[E0495]: cannot infer an appropriate lifetime for autorefdue to conflicting requirements
--> src/main.rs:20:14
|
20 | points.iter().cycle()
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 19:10...
--> src/main.rs:19:10
|
19 | .map(|points| {
| __________^
20 | | points.iter().cycle()
21 | | })
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:20:7
|
20 | points.iter().cycle()
| ^^^^^^
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the expression is assignable:
expected [std::iter::Cycle<std::slice::Iter<'static, i32>>; 2]
found [std::iter::Cycle<std::slice::Iter<'_, i32>>; 2]
Here is a REPL with the code trying to make use of the arraymap: https://repl.it/repls/ShadowyStrikingFirm .
In your type declaration:
type IntegerCycle = Cycle<std::slice::Iter<'static, i32>>;
You say that you the underlying slices you use to build your iterators must have 'static lifetime, that is, they must live forever. Then you use literal arrays such as [1, 2] that, as all literals, have 'static' lifetime and all goes well:
let r: &'static [i32; 2] = &[1, 2]; //Ok
But then, you try a code similar to this simpler one:
let a = [1, 2].map(|x| 2 * x);
let r: &'static [i32; 2] = &a; //error: borrowed value does not live long enough
That is the result of arraymap::map is a normal array, not a literal one, so it does not have a 'static lifetime. It cannot be static because you are computing the values in runtime. It will live as long as necessary, in my case as long as the variable a.
In your case, since the returns of arraymap::map are not assigned to variables, they are temporary values and they are quickly dropped. But even if you assigned it to a local variable, you could not return a reference to it, because the local variable is dropped when the function ends.
The solution is to return an iterator that owns the value. Something like this works:
type IntegerCycle = Cycle<std::vec::IntoIter<i32>>;
fn generate_cycles() -> [IntegerCycle; 2] {
let cycles = [
[1, 2],
[2, 4],
];
cycles
.map(|points| {
points.map(|point| point*2)
})
.map(|points| {
points.to_vec().into_iter().cycle()
})
}
Unfortunately you have to use a Vec instead of an array, because there is not an IntoIterator implementation for arrays, (there are for slices, but they do not own the values).
If you want to avoid the extra allocation of Vec you can use the arrayvec crate that does allow to take an iterator to an array:
type IntegerCycle = Cycle<arrayvec::IntoIter<[i32; 2]>>;
fn generate_cycles() -> [IntegerCycle; 2] {
let cycles = [
[1, 2],
[2, 4],
];
cycles
.map(|points| {
points.map(|point| point*2)
})
.map(|points| {
let a = arrayvec::ArrayVec::from(*points);
a.into_iter().cycle()
})
}
NOTE: It looks like there is an attempt to add a proper IntoIterator impl for arrays by value to the std, but there are still some pending issues.

Moving ownership to a std::io::Chain

I have a Reader that I want to prepend some bytes to, creating a Chain. Ideally I'd want to do this:
use std::io::{Chain, Read};
fn thingify<R: Read>(r: R) -> Chain<[u8; 3], R> {
let mut arr = [1u8, 2u8, 3u8];
// Modify arr here
return arr.chain(r);
}
But that throws a compiler error:
error[E0308]: mismatched types
--> test.rs:7:12
|
3 | fn thingify<R: Read>(r: R) -> Chain<[u8; 3], R>
| ----------------- expected `std::io::Chain<[u8; 3], R>` because of return type
...
7 | return arr.chain(r);
| ^^^^^^^^^^^^ expected array of 3 elements, found &[u8]
|
= note: expected type `std::io::Chain<[u8; 3], _>`
found type `std::io::Chain<&[u8], _>`
From what I understand, this seems to be because Read is implemented for slices rather than arrays, and somehow my array decays to a slice here.
But when I change the array in the return type to a slice and give it an explicit lifetime like so:
use std::io::{Chain, Read};
fn thingify<'a, R: Read>(r: R) -> Chain<&'a [u8], R> {
let arr = [1u8, 2u8, 3u8];
// Modify arr here
return arr.chain(r);
}
I just get another compiler error instead:
error[E0515]: cannot return value referencing local variable `arr`
--> test.rs:19:12
|
19 | return arr.chain(r);
| ---^^^^^^^^^
| |
| returns a value referencing data owned by the current function
| `arr` is borrowed here
How can I transfer ownership of my array to the Chain so that I can return it? Is that simply not doable with a [u8]?
Because Read is implemented for &'_ [u8] but not for [u8; 3], the compiler automatically converts your array into a reference slice. This mean your array must be valid as long as the slice live so as long as the Chain live.
There are several solutions, you could ask to the caller a mutable slice, you could make it static if you want to be able to mutate it, if you don't you can make it const, if you need to resize it you need a Vec, etc...
use std::io::{stdin, Chain, Read};
fn a<R: Read>(arr: &mut [u8; 3], r: R) -> Chain<&[u8], R> {
arr.copy_from_slice(&[1, 2, 3]);
arr.chain(r)
}
fn b<R: Read>(r: R) -> Chain<&'static [u8], R> {
const ARR: [u8; 3] = [1, 2, 3];
ARR.chain(r)
}
fn main() {
let mut arr = [0; 3];
println!("{:?}", a(&mut arr, stdin()));
println!("{:?}", b(stdin()));
}
See:
Is there any way to return a reference to a variable created in a function?

Why does Rust not recognize that I re-assign to the moved variable inside a closure?

I am having trouble understanding why a particular pattern is not compiling.
Rust recognizes when I move a variable and then reassign to it outside of a closure and I think properly allows the code to compile, but when I try to do the same in a closure that will be run more than once it will not.
fn main() {
let mut v = vec![1, 2, 3, 4];
v.into_iter().fold(0, |a, b| a + b);
v = vec![1, 2, 3, 4];
vec![1, 2, 3].into_iter().for_each(|x| {
v.into_iter().fold(x, |a, b| a + b);
v = vec![1, 2, 3, 4];
});
}
error[E0507]: cannot move out of captured outer variable in an `FnMut` closure
--> src/main.rs:6:9
|
2 | let mut v = vec![1, 2, 3, 4];
| ----- captured outer variable
...
6 | v.into_iter().fold(x, |a, b| a + b);
| ^ cannot move out of captured outer variable in an `FnMut` closure
It seems to me that the reassignment to v should satisfy the borrow checker that no variable will be accessed after being moved. Am I missing something?
As #Shepmaster mentioned, the fix is to use std::mem::replace.
So, what is the difference between:
v.into_iter().fold(x, |a, b| a + b);
v = vec![1, 2, 3, 4];
and:
let v_old = std::mem::replace(&mut v, vec![1, 2, 3, 4]);
v_old.into_iter().fold(x, |a, b| a + b);
?
In two words: exception safety.
If, for some reason, the expression v.into_iter().fold(...) would panic, it would leave v moved out and the next statement would never be executed.
This is perfectly acceptable in a FnOnce, as you will never call the closure another time, but not acceptable in a FnMut or Fn as on the next call... what would you do with v?
On the other hand, using std::mem::replace, you swap first and then execute the potentially panicking operation. If the operation does panic, then all that is left "moved out" is a temporary variable which disappears at the end of the stack frame anyway. No issue.
the reassignment to v should satisfy the borrow checker that no variable will be accessed after being moved
Pay attention to the error message details — there isn't a move to start with:
cannot move out of captured outer variable in an `FnMut` closure
Since there was no move out, it doesn't make sense to move something back in.
Instead, you can replace the value through the mutable reference and consume the old value:
fn main() {
let mut v = vec![1, 2, 3, 4];
vec![1, 2, 3].into_iter().for_each(move |x| {
let v_old = std::mem::replace(&mut v, vec![1, 2, 3, 4]);
v_old.into_iter().fold(x, |a, b| a + b);
});
}

Borrow a section of a borrowed array as a borrowed array

As the title reads, how would I go about doing this?
fn foo(array: &[u32; 10]) -> &[u32; 5] {
&array[0..5]
}
Compiler error
error[E0308]: mismatched types
--> src/main.rs:2:5
|
2 | &array[0..5]
| ^^^^^^^^^^^^ expected array of 5 elements, found slice
|
= note: expected type `&[u32; 5]`
= note: found type `&[u32]`
arrayref implements a safe interface for doing this operation, using macros (and compile-time constant slicing bounds, of course).
Their readme explains
The goal of arrayref is to enable the effective use of APIs that involve array references rather than slices, for situations where parameters must have a given size.
and
let addr: &[u8; 16] = ...;
let mut segments = [0u16; 8];
// array-based API with arrayref
for i in 0 .. 8 {
segments[i] = read_u16_array(array_ref![addr,2*i,2]);
}
Here the array_ref![addr,2*i,2] macro allows us to take an array reference to a slice consisting of two bytes starting at 2*i. Apart from the syntax (less nice than slicing), it is essentially the same as the slice approach. However, this code makes explicit the need for precisely two bytes both in the caller, and in the function signature.
Stable Rust
It's not possible to do this using only safe Rust. To understand why, it's important to understand how these types are implemented. An array is guaranteed to have N initialized elements. It cannot get smaller or larger. At compile time, those guarantees allow the size aspect of the array to be removed, and the array only takes up N * sizeof(element) space.
That means that [T; N] and [T; M] are different types (when N != M) and you cannot convert a reference of one to the other.
The idiomatic solution is to use a slice instead:
fn foo(array: &[u32; 10]) -> &[u32] {
&array[0..5]
}
A slice contains a pointer to the data and the length of the data, thus moving that logic from compile time to run time.
Nightly Rust
You can perform a runtime check that the slice is the correct length and convert it to an array in one step:
#![feature(try_from)]
use std::convert::TryInto;
fn foo(array: &[u32; 10]) -> &[u32; 5] {
array[0..5].try_into().unwrap()
}
fn main() {}
Unsafe Rust
Because someone might want to do this the unsafe way in an earlier version of Rust, I'll present code based on the standard library implementation:
fn foo(array: &[u32; 10]) -> &[u32; 5] {
let slice = &array[0..5];
if slice.len() == 5 {
let ptr = slice.as_ptr() as *const [u32; 5];
unsafe { &*ptr }
} else {
panic!("Needs to be length 5")
}
}
fn main() {
let input = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let output = foo(&input);
println!("{:?}", output);
}

Resources