2

I have a vector of numbers and use the windows(2) method to create an iterator that gives me neighbouring pairs. For example, the vector [1, 2, 3] is transformed into [1, 2], [2, 3]. I want to use the find method to find a slice that fulfills a specific condition:

fn step(g: u64) -> Option<(u64, u64)> {
    let prime_list: Vec<u64> = vec![2, 3, 5, 7]; //For example
    if prime_list.len() < 2 {
        return None;
    }
    let res = prime_list.windows(2).find(|&&[a, b]| b - a == g)?;
    //...
    None
}

I get an error:

error[E0005]: refutable pattern in function argument: `&&[]` not covered
 --> src/lib.rs:6:43
  |
6 |     let res = prime_list.windows(2).find(|&&[a, b]| b - a == g)?;
  |                                           ^^^^^^^^ pattern `&&[]` not covered

I don't know what that error means: the list cannot have less than two elements, for example. Maybe the closure parameter is wrong? I tried to vary it but that didn't change anything. a and b are being properly detected as u64 in my IDE too. What is going on here?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Pux
  • 421
  • 3
  • 18

1 Answers1

4

You, the programmer, know that each iterated value will have a length of 2, but how do you know that? You can only tell that from the prose documentation of the function:

Returns an iterator over all contiguous windows of length size. The windows overlap. If the slice is shorter than size, the iterator returns no values.

Nowhere does the compiler know this information. The implementation of Windows only states that the iterated value will be a slice:

impl<'a, T> Iterator for Windows<'a, T> {
    type Item = &'a [T];
}

I'd convert the slice into an array reference, discarding any slices that were the wrong length (which you know cannot happen):

use std::convert::TryFrom;

fn step(g: u64) -> Option<(u64, u64)> {
    let prime_list: Vec<u64> = vec![2, 3, 5, 7]; // For example

    if prime_list.len() < 2 {
        return None;
    }

    let res = prime_list
        .windows(2)
        .flat_map(<&[u64; 2]>::try_from)
        .find(|&&[a, b]| b - a == g)?;
    //...
    None
}

See also:

Alternatively, you could use an iterator of integers and chunk it up.

See also:

At some point in the future, const generics might be stabilized and allow baking the array length into the function call and the return type.

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366