Function that accepts multidimensional arrays as nested IntoIterator

Hi there,

I've been trying to create a single function that accepts a nested array (aka matrix) defined as a sized slice, vec of vec, or an unsized structure made up of arrays of references. I feel I'm close but cannot get past the following error:

cannot move out of `*row` which is behind a shared reference

This is the code (it works as long as we comment out the marked lines):

fn do_something<'a, T, U, V>(matrix: &'a T)
where
    T: ?Sized,
    &'a T: std::iter::IntoIterator<Item = &'a U>,
    U: 'a + std::fmt::Debug + std::iter::IntoIterator<Item = V>,
    V: std::fmt::Display,
{
    for row in matrix.into_iter() {
        println!("{:?}", row);
        // for val in row.into_iter() {
        //     println!("{}", val);
        // }
    }
}

fn main() {
    let a = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]];
    let b = vec![
        vec![0.1, 0.2, 0.3],
        vec![0.4, 0.5, 0.6],
        vec![0.7, 0.8, 0.9],
    ];
    let c: &[&[f64]] = &[
        &[10.0, 20.0, 30.0],
        &[40.0, 50.0, 60.0],
        &[70.0, 80.0, 90.0],
    ];
    do_something(&a);
    do_something(&b);
    do_something(c);
}

Ideally, I'd like to loop over the values as in the commented lines. Note that a, b, and c are the three different inputs that the function would accept. Maybe this is not possible? Or maybe there is a trait bound that would solve the problem?

Any help is much appreciated.
Cheers.

Here's one way for the given example:

+use core::borrow::Borrow;
+
 fn do_something<'a, T, U, V>(matrix: &'a T)
 where
     T: ?Sized,
     &'a T: std::iter::IntoIterator<Item = &'a U>,
-    U: 'a + std::fmt::Debug + std::iter::IntoIterator<Item = V>,
+    U: 'a + std::fmt::Debug + Borrow<[V]>,
     V: std::fmt::Display,
 {
     for row in matrix.into_iter() {
         println!("{:?}", row);
-        for val in row.into_iter() {
+        for val in row.borrow().into_iter() {
             println!("{}", val);
         }
     }
 }

Taking advantage of the blanket implementations of Borrow to accept either a reference or an owned value. It does come with other restrictions, but if those are too onerous, perhaps it can inspire some use-case specific traits.

2 Likes

Thanks a lot!