What does a scoped lifetime in rust actually mean?

前端 未结 1 1268
忘了有多久
忘了有多久 2021-02-10 00:57

So, in:

fn v1<\'a> (a:~[&\'a str]) -> ~[&\'a str] {
  return a;
}

#[test]
fn test_can_create_struct()          


        
1条回答
  •  情书的邮戳
    2021-02-10 01:28

    So the easiest way to answer this will be to take a step back and walk you through what a lifetime actually is.

    Lets take a simple function:

    fn simple_function() {
      let a = MyFoo::new();
      println("{}", a);
    }
    

    In this function, we have a variable, a. This variable, like all variables, lives for a certain amount of time. In this case, it lives to the end of the function. When the function ends, a dies. The lifetime of a, can then be described as starting at the beginning of the function, end ending at the end of the function.

    This next function won't compile:

    fn broken_function() -> &MyFoo {
      let a = MyFoo::new();
      return &a;
    }
    

    When you do &a, you are borrowing a reference to a. The thing about borrowing, though, is that you are expected to give the thing you borrowed back. Rust is very strict about this, and won't let you have references you can't return. If the thing you borrowed your reference from isn't around any more, you can't return the reference and that's just not on.

    What it means for our broken_function is that, because a dies at the end of the function, the reference can't escape the function, because that would make it outlast a.

    The next step is this:

    fn call_fn() {
      let a = MyFoo:new();
      {
        let a_ref = &a;
        let b = lifetimed(a_ref);
    
        println!("{}", *b);
      }
    }
    
    fn lifetimed<'a>(foo: &'a MyFoo) -> &'a MyBar {
       return foo.as_bar();
    }
    

    Here are two functions, call_fn and lifetimed, there's some subtle stuff going on here, so I'll break it down.

    In call_fn I first create a new instance of MyFoo and assign it to a, then, I borrow a reference to a and assign it to a_ref. The thing with borrowing is that when you do a borrow, the lifetime information is transfered from the variable you are borrowing, into the reference itself. So now a_ref, as a variable, has its own lifetime, which starts and ends at the beginning and end of that inner scope, but the type of a_ref also has a lifetime, the one transferred over from a.

    Concrete lifetimes can't be named, but lets pretend we can do it anyway by using numbers. If the lifetime of a is #1, then the type of a_ref is &'#1 MyFoo. When we pass a_ref to lifetimed, the compiler fills in the lifetime parameter 'a like it does for other type parameters. lifetimed's return type is a reference with the same lifetime, so the compiler fills in the space there. Effectively making a unique call to lifetimed(foo: &'#1 MyFoo) -> &'#1 MyBar.

    This is why lifetimes appear in the type parameter list, they are part of the type system, and if the types don't match up, that's an error. The compiler works out the lifetimes needed in order for the function to compile, so you never have to worry about it, but won't look outside the current function to get more information. You need to use the parameters to tell the compiler about the function you're calling so it knows that everything is ok.


    NB: There is one lifetime you can explicitly name. 'static which is the lifetime of things that last for the entire length of the program.

    0 讨论(0)
提交回复
热议问题