首先,以下代码是正确的:

fn main() {
    let a = &get_i32();
    println!("{}", a);
}
fn get_i32() -> i32 {
    return 100;
}

但以下代码出现错误:

fn main() {
    let a;
    a = &get_i32();
    println!("{}", a);
}
error[E0716]: temporary value dropped while borrowed
 --> src/bin/rust_course.rs:8:10
  |
8 |     a = &get_i32();
  |          ^^^^^^^^^- temporary value is freed at the end of this statement
  |          |
  |          creates a temporary value which is freed while still in use
9 |     println!("{}", a);
  |                    - borrow later used here
  |
help: consider using a `let` binding to create a longer lived value
  |
8 ~     let binding = get_i32();
9 ~     a = &binding;
  |

For more information about this error, try `rustc --explain E0716`.

这两段代码之间的本质区别是什么?我知道&get_i32()总是返回一个临时值,所以它应该总是报告一个错误.

一个类似的问题:

fn main() {
    let s1 = &String::from("hello world");
    println!("{}", s1);
    let s2 = String::from("hello world").as_str();
    println!("{}", s2);
}
error[E0716]: temporary value dropped while borrowed
 --> src/bin/rust_course.rs:6:14
  |
6 |     let s2 = String::from("hello world").as_str();
  |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^         - temporary value is freed at the end of this statement
  |              |
  |              creates a temporary value which is freed while still in use
7 |     println!("{}", s2);
  |                    -- borrow later used here
  |
help: consider using a `let` binding to create a longer lived value
  |
6 ~     let binding = String::from("hello world");
7 ~     let s2 = binding.as_str();
  |

For more information about this error, try `rustc --explain E0716`.

S1和S2有什么不同?

还有一个更类似的问题:


fn main() {
    print(String::from("hello world").as_str());
}

fn print(str: &str) {
    println!("{}", str);
}

上面的代码是正确的,但我不明白为什么String::from("hello world").as_str()可以传递给函数,而不能赋值给变量.

推荐答案

S1和S2有什么不同?

答案是temporary lifetime extension.遗憾的是,这是一个有点非正式的过程(正如页面所指出的,它可能会发生变化),但从广义上讲,用于绑定文字引用的let(因此&something)可以触发生命周期延长,而something将获得隐式临时引用.因此,let a = &get_i32();let s1 = &String::from("hello world");从中受益.

a = &get_i32();不起作用,因为TLE只对let起作用.

let s2 = String::from("hello world").as_str();也不会,因为临时变量的生命周期延长到statement的末尾,所以链基本上编译为块中的一系列调用,例如:

let s2 = {
    let _temp = String::from("hello world");
    _temp.as_str()
    // _temp is dropped here so `as_str` becomes invalid
};

但请注意,临时生命周期 到年底的statement,如果情况

print(String::from("hello world").as_str());

这一声明将持续到print年末,本质上是:

{
    let _temp1 = String::from("hello world");
    let _temp2 = _temp1.as_str();
    print(_temp2)
};

这完全没问题.

这也是为什么你可以写这样的东西:

    match &Some(String::new()).as_deref() {
        Some("") => println!("ok"),
        Some(_) => println!("??"),
        None => println!("ko"),
    }

整个match是一个单独的语句,所以Option<String>是临时的,直到它结束,这意味着我们可以同时引用内部和外部的值,并将&Option<&str>与我们从未绑定到任何地方的值一起使用(这是胡说八道的代码,但它展示了原理,这是我想到的第一件事).

然而,也有一些情况会导致问题,例如,如果您try borrow match,然后将原始值移动到其中一个分支中.这在非词汇生存期(和借阅判断)中变得不太常见了,但它仍然时不时地发生.

Rust相关问答推荐

即使参数和结果具有相同类型,fn的TypId也会不同

在HashMap中插入Vacant条目的可变借位问题

如何找到一个数字在二维数组中的位置(S)?

如何在Rust中实现Functor trait?

文档示例需要导入相关的 struct ,但仅在运行测试时.这是故意的行为吗?

如果成员都实现特征,是否在多态集合上实现部分重叠的特征?

限制未使用的泛型导致编译错误

如何指定不同的类型来常量Rust中的泛型参数?

Gtk4-rs:将监视器作为gdk::monitor获取,而不是作为glib::对象获取

为什么我们需要std::thread::scope,如果我们可以使用thread.join()在函数的生命周期内删除引用?

对于已经被认为是未定义行为的相同数据,纯粹存在`&;[u32]`和`&;mut[u32]`吗?

Rust面向对象设计模式

Rust 中多个 & 符号的内存表示

Rust typestate 模式:实现多个状态?

当 T 不是副本时,为什么取消引用 Box 不会抱怨移出共享引用?

判断 is_ok 后重用结果

Rust,我如何正确释放堆分配的内存?

具有生命周期和以后引用的可变方法

如何为返回正确类型的枚举实现 get 方法?

为什么我不能为 Display+Debug 的泛型类型实现 std::error::Error 但有一个不是泛型参数的类型?