Search code examples
multidimensional-arrayrustborrowing

How to convert ndarray::ArrayView to &ndarray::Array without copying?


I'm using the ndarray crate and I have a function that take a reference to Array2:

fn use_array(array: &Array2<u8>) {
    // ...
}

I'm trying to call this function with a view:

image.axis_iter(Axis(2)).for_each(|layer| {
    fun(&layer.to_owned());
});

It leads to an error:

   |
92 |         fun(&layer);
   |             ^^^^^^ expected struct `ndarray::OwnedRepr`, found struct `ndarray::ViewRepr`
   |
error: could not compile `poisson-editing`.
warning: build failed, waiting for other jobs to finish...
   = note: expected type `&ndarray::ArrayBase<ndarray::OwnedRepr<u8>, ndarray::dimension::dim::Dim<[usize; 2]>>`
              found type `&ndarray::ArrayBase<ndarray::ViewRepr<&u8>, ndarray::dimension::dim::Dim<[usize; 2]>>`

I can solve it by owning the array elements, but then I'm creating an unnecessary copy of the array.

image.axis_iter(Axis(2)).for_each(|layer| {
    use_array(&layer.to_owned());
});

Is there a way to avoid the copy here?


Update:

Now I consider it a foolish question. This conversion is not possible because you can not have &T without creating T. There is clearly no way to create Array2<u8> without retaining ownership over the underlying data. I deluded myself into thinking that it should be possible because both ArrayView and &Array does not own the data.


Solution

  • No, you can't obtain an &Array2<u8>, because an &Array2<u8> is always a reference to a full 2d array, while your layer contains additional metadata to identify the correct sections of the owned Array2 that are accessible.

    However, you could do it the other way around: You can make use_array take an ArrayView2<u8> (if it's not part of some external code you depend on) and then change any calls that previously called use_array with a full 2d array reference to use_array(your_array2.view()).