0

Playpen link: http://is.gd/EpX6lM

I have a closure that takes a slice and returns a subslice of it. Compiling the following code on rust-1.0.0-beta-2 fails:

trait OptionalFirst {
    fn optional_first<'a>(&self, x: &'a [usize]) -> &'a [usize];
}

impl<F> OptionalFirst for F where F: Fn(&[usize]) -> &[usize] {
    fn optional_first<'a>(&self, x: &'a [usize]) -> &'a [usize] {
        (*self)(x)
    }
}

fn main() {
    let bc: Box<OptionalFirst> = Box::new(
        |x: &[usize]| -> &[usize] {
            if x.len() != 0 {
                &x[..1]
            }
            else {
                &x[..0]
            }
        }) as Box<OptionalFirst>;

    let a: [usize; 3] = [1, 2, 3];
    let b: &[usize] = bc.optional_first(&a);
    println!("{:?}", b);
}

I know how to define a lifetime in a closure's type (using for <'a>), but I don't know how to specify it in the closure's implementation.

Chris Morgan
  • 86,207
  • 24
  • 208
  • 215
urubi
  • 847
  • 1
  • 9
  • 13
  • I'm not sure if the language has changed since the question was asked, or if the workaround always worked but just nobody thought of it at the time. In any case, I think the other questions and their answers better capture the problem and state of current solution space. – trent Feb 12 '22 at 02:03
  • (In case anyone is curious, [here's the workaround applied to this case](https://play.rust-lang.org/?version=beta&mode=debug&edition=2015&gist=dc39dcc4ca0ec3dac084e748c051ddef).) – trent Feb 12 '22 at 02:06

2 Answers2

4

Your implementation impl<F> OptionalFirst for F where F: Fn(&[usize]) -> &[usize] is expecting a bound lifetime parameter, for the constraint F: Fn(&[usize]) -> &[usize] is, expanded to full form: F: for<'a> Fn(&'a [usize]) -> &'a [usize].

That is, at the time you call the function, it will determine what values to select for the lifetime (they are generics).

A closure, however, cannot have any bound lifetime parameters; they are by stuck using concrete lifetime parameters. They lack the facility to wire output lifetimes to input lifetimes generically as you want: they are by very design concrete and not generic. I haven’t thought about this in great depth, but it might be possible to counteract this for generic lifetime parameters; it is not, however, something that is implemented as far as I am aware.

If you want something like this, try using a function rather than a closure. When you’re not using any of the environment there’s no benefit to using closures beyond the typically lower verbosity.

Here’s what you end up with:

fn bc(x: &[usize]) -> &[usize] {
    if x.len() != 0 {
        &x[..1]
    } else {
        &x[..0]
    }
}

Playpen

Chris Morgan
  • 86,207
  • 24
  • 208
  • 215
  • Thank you. Do you know where I can learn more about bound vs concrete lifetimes? I found a post on reddit, but it didn't help me much. – urubi Apr 18 '15 at 14:24
0

You can create a closure with bound lifetime parameters, you just have to get the compiler to infer that type correctly. It can be done like this:

fn main() {
    let bc: Box<Fn(&[usize]) -> &[usize]> = Box::new(
        |x| {
            if x.len() != 0 {
                &x[..1]
            }
            else {
                &x[..0]
            }
        });

    let a: [usize; 3] = [1, 2, 3];
    let b: &[usize] = bc(&a);
    println!("{:?}", b);
}

However, what I don't know is how to cast it further into Box<OptionalFirst>.

bluss
  • 12,472
  • 1
  • 49
  • 48