0
type Time = f32; type Behaviour<'a,T> = |Time|: 'a -> T; fn map_one<'a,T,R>(f: |T| -> R ,b: Behaviour<'a,T>) -> Behaviour<'a,R>{ |time| -> R { f(b(time)) } } 

Err:

<anon>:8:9: 8:10 error: captured variable `b` does not outlive the enclosing closure <anon>:8 f(b(time)) ^ <anon>:6:38: 10:2 note: captured variable is valid for the block at 6:37 <anon>:6 -> Behaviour<'a,R>{ <anon>:7 |time| -> R { <anon>:8 f(b(time)) <anon>:9 } <anon>:10 } 

I think the error means that the life time of 'a expires when I try to move b into another closure.

How would I express something like this?

1

1 Answer 1

1

Your code is using "boxed" closures. Those closures capture values by reference, so the captured value must live longer than the closure. You're trying to capture b, which is a parameter, so its lifetime is the duration of the function call. You cannot do what you want to do with "boxed closures.

Unboxed closures were added to the language to solve issues like this. Here's how map_one would be defined:

#![feature(overloaded_calls, unboxed_closures, unboxed_closure_sugar)] type Time = f32; fn map_one<'a, T, R, F: Fn<(T,), R>, B: Fn<(Time,), T>>( f: F, b: B) -> Box<Fn<(Time,), R>+'a> { box |&: time| -> R { f(b(time)) } } 

Fn is a trait with a call method that takes self by immutable reference (FnMut takes self by mutable reference and FnOnce takes self by value). The captured values are moved into the closure, rather than referenced.

The input closure parameters are defined with a type parameter that implements the Fn trait, which is the only way to pass closures by value. The return value, however, must be boxed, because the concrete result type (which implements Fn) is created by the compiler, and we can't name it.

I tried writing a main that uses map_one, but I'm getting an internal compiler error... At that point, I can't tell if I made a mistake or if the code is supposed to be valid. (These Rust issues may be related to this error: #16672, #16791, #17060.)

fn main() { let t = 30f32; let fa = |&: a: String| -> uint { a.len() }; let fb = |&: b: f32| -> String { b.to_string() }; let m = map_one(fa, fb); let r = m.call((t,)); println!("{}", r); } 

Note: I couldn't use your Behaviour generic type alias to bound B.

#![feature(overloaded_calls, unboxed_closures, unboxed_closure_sugar)] type Time = f32; type Behaviour<T> = Fn<(Time,), T>; fn map_one<'a, T, R, F: Fn<(T,), R>, B: Behaviour<T>>( f: F, b: B) -> Box<Behaviour<R>+'a> { box |&: time| -> R { f(b(time)) } } 

The compiler complains:

<anon>:6:41: 6:53 error: `Behaviour` is not a trait <anon>:6 fn map_one<'a, T, R, F: Fn<(T,), R>, B: Behaviour<T>>( ^~~~~~~~~~~~ <anon>:6:41: 6:53 note: `type` aliases cannot be used for traits <anon>:6 fn map_one<'a, T, R, F: Fn<(T,), R>, B: Behaviour<T>>( ^~~~~~~~~~~~ 
Sign up to request clarification or add additional context in comments.

1 Comment

With #[feature(unboxed_closure_sugar)] you can use |&:...| -> ... for Fn<(...), ...>. I'd also suggest using |&mut:...| -> ... (and FnMut<(...), ...>, correspondingly), as it is more general.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.