【问题标题】:How to initialize a variable with a lifetime?如何初始化具有生命周期的变量?
【发布时间】:2015-03-22 10:05:22
【问题描述】:

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

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

fn main() {
    let x = new_int();
}

或另一种尝试:

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

fn main() {
    let x = new_int();
}

【问题讨论】:

  • 我不知道你想做什么,但你正在做的是试图创建一个对生命周期小于 'a.它具有函数体的生命周期。
  • 我正在尝试使用生命周期参数将该变量暴露给身体外部。如果可能的话。
  • 该变量在函数体之外已失效。如果您可以访问它,您将覆盖其他内存。错误消息(请参阅is.gd/ju7hFZ)准确地告诉您。
  • 由于static 升级,这些函数现在进行编译(请参阅Why can I return a reference to a local literal but not a variable?

标签: rust lifetime


【解决方案1】:

你不能。生命周期参数不允许您选择一个值的生命周期,它只允许您与编译器沟通两个或多个引用与同一内存“相关”并且预计共享相同的生命周期。

一个函数(比如你的new_int)可以通过两种方式分配内存:

  • 本地分配给函数本身并在您从函数(堆栈)返回时销毁
  • 动态地在所有函数(堆)共用的内存区域中

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

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

fn new_int<'a>() -> &'a isize {
    let a: &'a isize = &5; // write 5 on the function's local stack
    a // return a pointer to that area of memory
} // the function ends and its stack (where I wrote 5) is destroyed
  // so the pointer I'm trying to return is no longer valid

你可以返回值

fn new_int() -> isize {
    5
}

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

或执行动态分配(这在 isize 的情况下是多余的,但如果您实际使用大型结构可能会有意义)

fn new_int() -> Box<isize> {
    Box::new(5) // a Box allocates memory and writes in the heap
}

fn main() {
    let a = *new_int();
}

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

// 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
}

作为@dk mentions in the comment below,,在这种特定情况下(即您的函数总是返回 5 或其他一些静态已知值,而不是由函数动态计算的值),您还可以返回具有 'static 生命周期的引用:

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

你可以阅读更多关于'staticin the Rust Reference的信息。

从 Rust 1.21 开始,这个“静态提升”现在会自动为您执行,并且您的原始代码可以编译。它创建了 static FIVE 的等价物。

【讨论】:

  • 放弃我自己正在进行的答案,但我想指出第三种选择:如果它总是返回5,或任何有限的答案集,你可以返回对静态变量的借用引用:static FIVE: isize = 5;,然后作为函数的结果返回 &amp;FIVE
【解决方案2】:

另一种理解原因的方法

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

不能工作如下。 'a 是函数的生命周期参数;也就是说,选择这个参数的实际值的是调用者,而不是函数本身。比如调用者可以选择'staticlifetime:

let i: &'static isize = new_int();

但是,&amp;5 不能拥有 'static 生命周期,因此该函数被拒绝。

换句话说,这样的声明本质上是说“我可以给你一个你想要的任何生命周期的参考”。当然,这仅在函数返回的引用为 'static 生命周期(这是可能的最大生命周期)时才有效。这就是DK。顺便说一句。

【讨论】:

    【解决方案3】:

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

    它们不是让某些东西按要求生存下去的指令,而是一种一致性检查,可确保代码确实按照它所说的那样工作。

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

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

    【讨论】:

      猜你喜欢
      • 2019-02-08
      • 1970-01-01
      • 2023-03-27
      • 1970-01-01
      • 2018-06-06
      • 1970-01-01
      • 2016-12-25
      • 2016-12-10
      • 2021-12-12
      相关资源
      最近更新 更多