如何初始化具有生命周期的变量?
Posted
技术标签:
【中文标题】如何初始化具有生命周期的变量?【英文标题】: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?
【参考方案1】:
你不能。生命周期参数不允许您选择一个值的生命周期,它只允许您与编译器沟通两个或多个引用与同一内存“相关”并且预计共享相同的生命周期。
一个函数(比如你的new_int
)可以通过两种方式分配内存:
引用 (&
) 是指向内存区域的指针。它可以指向本地堆栈或堆。由于动态分配在性能方面比在堆栈上写入要昂贵得多,因此 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
你可以阅读更多关于'static
in the Rust Reference的信息。
从 Rust 1.21 开始,这个“静态提升”现在会自动为您执行,并且您的原始代码可以编译。它创建了 static FIVE
的等价物。
【讨论】:
放弃我自己正在进行的答案,但我想指出第三种选择:如果它总是返回5
,或任何有限的答案集,你可以返回对静态变量的借用引用:static FIVE: isize = 5;
,然后作为函数的结果返回 &FIVE
。【参考方案2】:
另一种理解原因的方法
fn new_int<'a>() -> &'a isize
&5
不能工作如下。 'a
是函数的生命周期参数;也就是说,选择这个参数的实际值的是调用者,而不是函数本身。比如调用者可以选择'static
lifetime:
let i: &'static isize = new_int();
但是,&5
不能拥有 'static
生命周期,因此该函数被拒绝。
换句话说,这样的声明本质上是说“我可以给你一个你想要的任何生命周期的参考”。当然,这仅在函数返回的引用为 'static
生命周期(这是可能的最大生命周期)时才有效。这就是DK。顺便说一句。
【讨论】:
【参考方案3】:生命周期仅描述代码已经在做什么。它们不会以任何方式影响代码的行为。
它们不是让某些东西按要求生存下去的指令,而是一种一致性检查,可确保代码确实按照它所说的那样工作。
事实上,Rust 在检查代码后会从代码中剥离所有生命周期,然后在不知道生命周期的情况下编译代码。
变量在其作用域结束时被销毁,这就是它们的生命周期。你不能说他们没有这样做。
【讨论】:
以上是关于如何初始化具有生命周期的变量?的主要内容,如果未能解决你的问题,请参考以下文章