Ernest
Ernest

Reputation: 8829

How to reuse ranges for getting parts of arrays?

I am processing arrays in chunks of different sizes (3, 4, 5 etc.) (link to the playground):

fn main() {
    let arr: [u8; 10] = [
        1, 1, 1,
        2, 2, 2,
        3, 3, 3, 0
    ];
    let mut results: [u8; 10] = [0; 10];
    let corrections: [u8; 10] = [
        1, 1, 1,
        1, 1, 1,
        1, 1, 1, 0
    ];
    let group_ranges = vec![
        0..3,
        3..6,
        6..10
    ];

    for range in group_ranges {
        let group_sum: u8 = arr[&range].iter().sum();
        for (idx, el) in arr[&range].iter().enumerate() {
            results[&range][idx] = el * group_sum * corrections[&range][idx];
        }
    }
    println!("{:?}", results);
    // => [3, 3, 3, 12, 12, 12, 27, 27, 27, 0]
}

The errors returned:

error[E0277]: the trait bound `&std::ops::Range<{integer}>: std::slice::SliceIndex<[u8]>` is not satisfied
  --> src/main.rs:20:29
   |
20 |         let group_sum: u8 = arr[&range].iter().sum();
   |                             ^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize`
   |
   = help: the trait `std::slice::SliceIndex<[u8]>` is not implemented for `&std::ops::Range<{integer}>`
   = note: required because of the requirements on the impl of `std::ops::Index<&std::ops::Range<{integer}>>` for `[u8]`

error[E0277]: the trait bound `&std::ops::Range<{integer}>: std::slice::SliceIndex<[u8]>` is not satisfied
  --> src/main.rs:21:26
   |
21 |         for (idx, el) in arr[&range].iter().enumerate() {
   |                          ^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize`
   |
   = help: the trait `std::slice::SliceIndex<[u8]>` is not implemented for `&std::ops::Range<{integer}>`
   = note: required because of the requirements on the impl of `std::ops::Index<&std::ops::Range<{integer}>>` for `[u8]`

error[E0277]: the trait bound `&std::ops::Range<{integer}>: std::slice::SliceIndex<[u8]>` is not satisfied
  --> src/main.rs:22:13
   |
22 |             results[&range][idx] = el * group_sum * corrections[&range][idx];
   |             ^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize`
   |
   = help: the trait `std::slice::SliceIndex<[u8]>` is not implemented for `&std::ops::Range<{integer}>`
   = note: required because of the requirements on the impl of `std::ops::Index<&std::ops::Range<{integer}>>` for `[u8]`

error[E0277]: the trait bound `&std::ops::Range<{integer}>: std::slice::SliceIndex<[u8]>` is not satisfied
  --> src/main.rs:22:53
   |
22 |             results[&range][idx] = el * group_sum * corrections[&range][idx];
   |                                                     ^^^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize`
   |
   = help: the trait `std::slice::SliceIndex<[u8]>` is not implemented for `&std::ops::Range<{integer}>`
   = note: required because of the requirements on the impl of `std::ops::Index<&std::ops::Range<{integer}>>` for `[u8]`

Using range instead of &range yields the use of moved value error. Is it possible to work without using range.clone() all over?

Upvotes: 2

Views: 724

Answers (1)

Shepmaster
Shepmaster

Reputation: 430991

No, it is not currently possible. The valid values to pass to a slice's index method (a.k.a. []) are those types which implement the SliceIndex trait. &Range is not in that list, although I don't know if there's any technical reason that prevents it from being the case.

An aside on the performance of cloning in this case...

When you call foo[1..2], you are passing ownership of the created Range<usize> into Index::index, which takes up two usize values. If we were able to pass in a &Range, we'd only be passing in a single usize worth, but we'd have to perform a dereference and then probably copy at least one of the inner usizes anyway. My (untested) hypothesis is that it would be slower than cloning anyway.

See also

Upvotes: 4

Related Questions