简体   繁体   English

如何理解 Rust 中函数参数和返回值的生命周期?

[英]How to understand the lifetime of function parameters and return values in Rust?

I'm a newbie in Rust and I'm still struggling with lifetime in Rust.我是 Rust 的新手,我仍然在 Rust 中苦苦挣扎。 The Rust Programming Language book defines lifetime as Rust 编程语言一书将生命周期定义为

the scope for which that reference is valid该引用有效的范围

It's easy to understand when the context is a single function.当上下文是单个函数时很容易理解。 For example, in the below code, the lifetime of s is the blue box, the lifetime of x is the green box etc.例如,在下面的代码中,s 的生命周期是蓝色框,x 的生命周期是绿色框等等。

在此处输入图片说明

When it comes to functions, I don't quite understand what exactly does the lifetime mean for function parameters and return values.说到函数,我不太明白生命周期对于函数参数和返回值到底意味着什么。 Let's say we have this function:假设我们有这个功能:

fn parse_record<'i>(input: &'i [u8]) -> Record<'i> { ... }

The signature states that the input parameter and the return value Record must have the same lifetime 'i .签名声明input参数和返回值Record必须具有相同的生命周期'i Does that mean when we are calling the function, the value we passed into the function and the returned value must have the same lifetime?这是否意味着当我们调用函数时,我们传递给函数的值和返回值必须具有相同的生命周期? For example, I may invoke the function in main function like this:例如,我可以像这样调用main函数中的函数:

fn main() {
    let mut v: Vec<u8> = [1_u8, 2_u8, 3_u8].to_vec();
    let result = parse_record(&v);
    // use v and result ...
}

Does the lifetime in the function signature state that v and result in main must have the same lifetime?函数签名中的生命周期是否声明vresult main必须具有相同的生命周期?

I would like to clarify here, citing Rust by Example我想在这里澄清一下,引用Rust by Example

A lifetime is a construct the compiler (or more specifically, its borrow checker) uses to ensure all borrows are valid.生命周期是编译器(或更具体地说,其借用检查器)用来确保所有借用有效的构造。 Specifically, a variable's lifetime begins when it is created and ends when it is destroyed.具体来说,变量的生命周期从创建时开始,到销毁时结束。 While lifetimes and scopes are often referred to together, they are not the same.虽然生命周期和作用域经常一起被引用,但它们并不相同。

Take, for example, the case where we borrow a variable via &.以我们通过 & 借用变量为例。 The borrow has a lifetime that is determined by where it is declared.借用的生命周期由它的声明位置决定。 As a result, the borrow is valid as long as it ends before the lender is destroyed.因此,只要在贷方被销毁之前结束,借入就是有效的。 However, the scope of the borrow is determined by where the reference is used.但是,借用的范围取决于引用的使用位置。

It seems that Rust book created a lot of confusion, but scope and lifetime are indeed different things, when we talk about simple bindings which own data (not borrow it) lifetime and scope match together.看起来 Rust 书造成了很多混乱,但是当我们谈论拥有数据(而不是借用它)生命周期和范围匹配的简单绑定时, scopelifetime确实是不同的东西。

If we have simple code like this.如果我们有这样的简单代码。 Lifetime of a and b will match with scope they are defined. ab生命周期将与它们定义的范围相匹配。

fn main() {
    let a = 1;
    let b = 2;
}

In this example, lender ( a ) goes out of scope sooner than borrow.在此示例中,贷方 ( a ) 比借入更早地超出范围。

fn main() {

    let b;
    {
        let a = 1;
        b = &a;
    }
    let c = *b;
}

It forces compiler to emit error.它强制编译器发出错误。


error[E0597]: `a` does not live long enough
 --> src/main.rs:5:9
  |
5 |         b = &a;
  |         ^^^^^^ borrowed value does not live long enough
6 |     }
  |     - `a` dropped here while still borrowed
7 |     let c = *b;
  |             -- borrow later used here

So here b has a lifetime longer than the lifetime of a , because it has a greater scope.因此,这里b具有寿命比寿命更长的a ,因为它有一个更大的范围内。 Remember that scope of borrow is determined by where the reference is used.请记住,借用的范围由使用引用的位置决定。

But this code compiles just fine, because b scope doesn't end after a is dropped.但是这段代码编译得很好,因为b范围在a被删除后不会结束。

fn main() {
    let b;
    {
        let a = 1;
        b = &a;
        let c = *b;
    }
}

Another thing to clarify is that lifetime syntax for reference &'lifetime means.另一件需要澄清的事情是引用&'lifetime周期语法意味着。 It means that reference should live as long as 'lifetime lifetime.这意味着引用应该与'lifetime周期'lifetime一样长。 It shouldn't be exactly that lifetime.不应该是那样的一生。

Suppose Record element is defined like this.假设Record元素是这样定义的。

struct Record<'a> {
   some_member: &'a Type
}

This signature just means that some member of record should live as long as reference passed to input or vice versa.这个签名只是意味着记录的某个成员应该只要引用传递给input应该存在,反之亦然。

fn parse_record<'i>(input: &'i [u8]) -> Record<'i> { ... }

If I translate it to plain English.如果我把它翻译成简单的英语。 Lender of the reference passed to the function shouldn't go out of scope (dropped) as long as a field inside Record didn't go out of scope.只要Record的字段没有超出范围,传递给函数的引用的贷方就不应超出范围(删除)。

Or return value of function should live as long as input argument of function.或者函数的返回值应该与函数的输入参数一样长。

If we don't have return value which is constrained by the input lifetime, translation changes.如果我们没有受输入生命周期约束的返回值,则翻译会发生变化。

fn test<'a>(a: &'a i32, b: &'a i32)

This means that lenders of a and b should be in scope together until function execution ends.这意味着ab贷方应该一起在作用域内,直到函数执行结束。

In many simple cases lifetimes are elided by compiler and you shouldn't worry about them.在许多简单的情况下,编译器会忽略生命周期,您不必担心它们。 Actually in your example too, lifetimes can be elided.实际上,在您的示例中,也可以省略生命周期。

fn parse_record(input: &[u8]) -> Record { ...  }

I recommend you to read Rust by Example chapters on lifetimes to more practically understand them.我建议你阅读Rust by Example关于生命周期的章节,以更实际地理解它们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM