是否可以返回在函数范围内创建的引用?

时间:2016-09-17 19:15:25

标签: rust lifetime

我有一个相当简单的程序:

fn f<'a>() -> &'a i32 {
    &1
}

fn main() {
    println!("{}", f());
}

它没有编译(某些输出被省略):

$ rustc test.rs
test.rs:2:6: 2:7 error: borrowed value does not live long enough
test.rs:2     &1

我明白为什么失败了。

  1. 我不知道如何返回在函数范围内创建的引用。有办法吗?
  2. 为什么单一回报的生命不能被遗弃?
  3. 编辑:我更改了标题,因为它建议返回盒装类型会有所帮助(请参阅答案)。

3 个答案:

答案 0 :(得分:2)

由于Rust使用RAII样式的资源管理,因此只要程序离开作用域,该作用域内未移动的所有值都将被销毁。值必须存在于某处才能使引用有效。因此,要么返回这样的值(如果您担心在执行此操作时有额外的副本,那么请不要担心,因为该副本将被优化掉)或将其装箱并返回框。除非您按如下方式将静态分配的字符串作为&str返回,否则您根本无法返回&#34; new&#34; (对于来电者)参考:

fn f<'a>() -> &'a str {
    "yo"
}

答案 1 :(得分:2)

装箱参考将无济于事。在大多数方面,Box<T>几乎与未装箱的T相同,包括所有权和终身问题。根本问题是局部变量将在函数返回后立即停止存在。因此,对于局部变量的引用将指向在调用函数获取该引用时的解除分配的内存。将包装纸放在参考物周围并不能解决这个问题。

我认为这是一个简单的例子,它来自你遇到麻烦的真实程序。由于缺乏信息,我无法为此提供有针对性的建议,但通常按价值返回内容(例如,在这种情况下只是-> i32)是一个非常好的主意参考。

答案 2 :(得分:1)

Rust 1.21开始,名为rvalue static promotion的新功能意味着问题中的代码现在已经编译。

在此实例中,因为1是常量,编译器会将其提升为static,这意味着返回的引用具有'static生存期。脱糖功能看起来像:

fn f<'a>() -> &'a i32 {
    static ONE: i32 = 1;
    &ONE
}

这适用于任何编译时常量,包括结构:

struct Foo<'a> {
    x: i32,
    y: i32,
    p: Option<&'a Foo<'a>>
}

fn default_foo<'a>() -> &'a Foo<'a> {
    &Foo { x: 12, y: 90, p: None }
}

但这不会编译:

fn bad_foo<'a>(x: i32) -> &'a Foo<'a> {
    /* Doesn't compile as x isn't constant! */
    &Foo { x, y: 90, p: None }
}