Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I create an array of unboxed functions / closures?

Editor's note: This question was asked before Rust 1.0 and some of the syntax has changed since then, but the underlying concepts remain. Some answers have been updated for Rust 1.0 syntax.

I'm new to Rust and trying to do something with closures which is trivial in JavaScript, Python, etc. but I am running into lifetime issues in Rust. I understand the error message, but it leads me to believe what I want to do is pretty hard in Rust.

I just want to create an array of functions, a, such that

  • a[0] is the function returning 0
  • a[1] is the function returning 1
  • ...
  • a[9] is the function returning 9

I tried:

fn main() {
    let a : [||->uint,  ..10];
    for i in range(0u, 10) {
        a[i] = ||{i};
    }
    println!("{} {} {}", a[1](), a[5](), a[9]())
}

But I got a lifetime error. The reported error was "cannot infer an appropriate lifetime due to conflicting requirements" for the functions in a because the lifetimes cannot outlive the while block so that the closures cannot outlive their stack frame, which of course they would because I am invoking them in println!.

I'm sure there must be a way to build up this array of functions, but how?

like image 825
Ray Toal Avatar asked Dec 15 '14 19:12

Ray Toal


2 Answers

You need to use move || i.

move implies that this closure will take i by value rather than by reference. By default, these closures would only take references to i. In your case it is forbidden as the lifetime of i is limited to the body of the loop.

Also, Rust will complain that your array may not be fully initialized. To avoid it, you can either use a Vec<_>, or use std::mem::uninitialized:

fn main() {
    let mut a: [_; 10] = unsafe { std::mem::uninitialized() };
    for i in 0..10 {
        a[i] = move || i;
    }
    println!("{} {} {}", a[1](), a[5](), a[9]())
}
like image 198
Levans Avatar answered Nov 17 '22 22:11

Levans


It is possible to collect multiple closures from an iterator into a Vec:

fn main() {
    let a: Vec<_> = (0..10).map(|i| move || i).collect();

    println!("{} {} {}", a[1](), a[5](), a[9]());
}

The move keyword causes ownership of i to be transferred to the closure.

See also:

  • How do I collect into an array?
like image 4
Shepmaster Avatar answered Nov 17 '22 23:11

Shepmaster