rust - Code working with elided lifetimes, not with explicit -


the following code works fine:

fn get<f: fn(&[u8]) -> u8>(f: f) -> u8 {     f(&[1, 2, 3]) } 

however, when add explicit lifetime information it, doesn't:

fn get<'inp, f: fn(&'inp [u8]) -> u8>(f: f) -> u8 {     f(&[1, 2, 3]) } 

what lifetime compiler infer in working code?

i'm using rust 1.18.0.

the error message is:

error: borrowed value not live long enough  --> test.rs:4:8   | 4 |     f(&[1, 2, 3])   |        ^^^^^^^^^ not live long enough 5 | }   | - temporary value lives until here   | note: borrowed value must valid lifetime 'inp defined on body @ 3:49...  --> test.rs:3:50   | 3 |   fn get<'inp, f: fn(&'inp [u8]) -> u8>(f: f) -> u8 {   |  __________________________________________________^ 4 | |     f(&[1, 2, 3]) 5 | | }   | |_^ 

lifetimes in trait bounds bit special , fn family of traits has special lifetime elision rule. we'll dive that, first, here correct explicitly annotated version:

fn get<f: for<'inp> fn(&'inp [u8]) -> u8>(f: f) -> u8 {     f(&[1, 2, 3]) } 

oh gosh, for<'inp> doing there? it's called higher ranked trait bound (hrtb) , it's used here make 'inp universally quantiefied in regards f. in order understand that, need understand bit of theory.


who has choice?

let's take @ easy example:

fn bar<'a>(x: &'a u8) {} 

here, bar() generic of lifetime 'a. syntax above reads: "choose 'a , there bar() work 'a". means can choose 'a want, , bar() works! "we"? "we" caller -- 1 calling bar. important later: caller chooses generic parameters. can call bar() &'static u8 reference doesn't live long.

now might ask: there situations caller doesn't choose generic parameter, else does? yes, there are! sadly, it's bit more difficult understand, because doesn't occur in today's rust code. let's try:

trait bar<'a> {     fn bar(&self, x: &'a u8); } 

this similar bar() function above, lifetime parameter defined on trait, not function. let's use trait:

fn use_bar<'a, b: bar<'a>>(b: b) {     let local = 0u8;     b.bar(&local); } 

this doesn't compile, printing same error above. why? method b.bar() expects reference of lifetime 'a. chooses 'a here? exactly: caller -- caller of use_bar(), not caller of bar()! caller of use_bar() choose 'static lifetime; in case, it's easy see our &local doesn't fulfill lifetime requirements.

note caller of use_bar() chooses 'a b. once use_bar() instantiated, b fixed type , b::bar() works 1 specific lifetime. means caller of bar() can't choose lifetime, bar() chose it!

what want instead? want use_bar() choose lifetime of bar() call. , can for<> syntax:

fn use_bar<b: for<'a> bar<'a>>(b: b) {     let local = 0u8;     b.bar(&local); } 

this works. here is: "for lifetime parameter 'a, b has implement trait bar<'a>". instead of: "there needs exist lifetime parameter 'a b implements bar<'a>". it's chooses parameter.

let's use real names it:

  • a generic parameter universally quantified if caller can choose it
  • a generic parameter existentially quantified if callee can choose it

what rust do?

to return example:

fn get<'inp, f: fn(&'inp [u8]) -> u8>(f: f) -> u8 {     f(&[1, 2, 3]) } 

here have same problem above: lifetime parameter of f existentially quantified. caller of f cannot choose lifetime parameter. can fix for<> syntax shown above.

when omit lifetimes:

fn get<f: fn(&[u8]) -> u8>(f: f) -> u8 {     f(&[1, 2, 3]) } 

the rust compiler special fn family of traits. f: fn(&[u8]) desugars f: for<'a> fn<(&'a [u8],)>. if use fn* traits parameters involve lifetimes, lifetimes automatically universally quantified, because that's want higher order functions.


Comments

Popular posts from this blog

Is there a better way to structure post methods in Class Based Views -

performance - Why is XCHG reg, reg a 3 micro-op instruction on modern Intel architectures? -

jquery - Responsive Navbar with Sub Navbar -