如何使用生命周期初始化变量?

Hin*_*ary 10 lifetime rust

我有以下代码,不知道如何让它工作:

fn new_int<'a>() -> &'a isize {
    &5
}

fn main() {
    let x = new_int();
}
Run Code Online (Sandbox Code Playgroud)

或者另一种尝试:

fn new_int<'a>() -> &'a isize {
    let a: &'a isize = &5;
    a
}

fn main() {
    let x = new_int();
}
Run Code Online (Sandbox Code Playgroud)

Pao*_*lla 13

你不能.生命周期参数不允许您选择值存在多长时间,它只允许您与编译器通信两个或多个引用与相同内存"相关"并且预期共享相同的生命周期.

函数(new_int在您的情况下)可以通过两种方式分配内存:

  • 在一个区域(堆栈)中本地分配给函数本身,并在从函数返回时被销毁
  • 动态地存储在所有函数共有的内存区域(通常称为"堆",尽管这在所有情况下都不一定正确)

参考(&)是指向内存区域的指针.它可以指向本地堆栈,也可以指向"堆".由于动态分配在性能方面比在堆栈上写入要昂贵得多,因此Rust默认使用堆栈(您必须使用Box来执行动态分配).

因此,简而言之,这就是您的代码非法的原因:

fn new_int<'a>() -> &'a isize {
    let a: &'a isize = &5; // write 5 on the local stack
    a // return a pointer to that area of memory
} // the area of memory where I wrote 5 is destroyed here,
  // so the pointer I'm trying to return is not valid
Run Code Online (Sandbox Code Playgroud)

您可以返回值

fn new_int() -> isize {
    5
}

fn main() {
    let a = new_int(); // the value 5 (not a pointer) is copied into a
}
Run Code Online (Sandbox Code Playgroud)

或执行动态分配(在isize的情况下是矫枉过正的,但如果您实际使用的是大型结构则可能有意义)

fn new_int() -> Box<isize> {
    Box::new(5)
}

fn main() {
    let a = *new_int();
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以在函数外部分配内存并在函数中对其进行变更.您通常不会为原始类型执行此操作,但在某些情况下(例如,数据流)有意义:

// new_int does not return anything. Instead it mutates
// the old_int in place
fn new_int(old_int: &mut isize) {
    *old_int = 5;
}

fn main() {
    let mut a = 2; // memory for an int is allocated locally
                   // in main()
    new_int(&mut a); // a mutable reference to that memory is passed
                     // to new_int, that overwrites it with another value
}
Run Code Online (Sandbox Code Playgroud)

正如@dk在下面的注释中提到的那样,在这种特定情况下(即你的函数总是返回5或其他一些静态已知值,而不是函数动态计算的东西),你也可以返回一个带有'static生命周期的引用:

fn new_int<'a>() -> &'a isize {
    static FIVE: isize = 5;
    &FIVE
}
Run Code Online (Sandbox Code Playgroud)

您可以static 在Rust Reference中阅读更多有关' 的信息.

从Rust 1.21开始,这个"静态促销"现在会自动为您执行并且您的原始代码会编译.它创造了相当于static FIVE.

  • 抛弃我自己正在进行的答案,但我想指出第三个选项:如果它总是*返回`5`,或任何有限的答案集,你可以返回一个借用的静态变量引用:`static FIVE: isize = 5;`,然后`&FIVE`作为函数的结果. (5认同)

Vla*_*eev 6

理解原因的另一种方法

fn new_int<'a>() -> &'a isize {
    &5
}
Run Code Online (Sandbox Code Playgroud)

不能正常工作如下.'a是函数的生命周期参数 ; 也就是说,调用者选择此参数的实际值,而不是函数本身.例如,调用者可以选择'static生命周期:

let i: &'static isize = new_int();
Run Code Online (Sandbox Code Playgroud)

但是,&5不能有'static生命,所以功能被拒绝.

换句话说,这种声明基本上是说"我可以给你一个你想要的任何生命的参考".当然,这仅在从函数返回的引用具有'static生命周期时才有效,这是可能的最大生命周期.这就是DK.顺便说一下.


Kor*_*nel 5

生命周期仅描述代码已经在做什么。它们不会以任何方式影响代码的行为。

它们并不是让某些东西按照需要的时间运行的指令,而是一种一致性检查,以确保代码确实按照其规定执行。

事实上,Rust 在检查后从代码中剥离所有生命周期,然后在不了解生命周期的情况下编译代码。

变量在其作用域结束时被销毁,这就是它们的生命周期。你不能说声明他们没有这样做。