rust - 为什么 Rust 的临时值有时是可引用的,有时却不是?

标签 rust temporary

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

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()可以传递给函数但不能赋值给变量。

最佳答案

What's the difference between s1 and s2?

答案是temporary lifetime extension 。遗憾的是,这是一个有点非正式的过程(正如页面指出的那样,它可能会发生变化),但从广义上讲,这就是 let用于绑定(bind)文字引用(因此 &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();也不是,因为临时变量的生命周期延长到语句的末尾,因此链本质上会编译为 block 中的一系列调用,例如:

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

但是请注意,临时存在于语句的末尾,以防出现

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>到一个我们从未绑定(bind)到任何地方的值(这是无意义的代码,但它显示了原理,这是我想到的第一件事)。

但是,也有一些情况会导致问题,例如你尝试 match借用后,将原始值移至其中一个分支。这种情况在非词法生命周期(和借用检查)中已经不太常见,但仍然时不时地发生。

关于rust - 为什么 Rust 的临时值有时是可引用的,有时却不是?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76362527/

相关文章:

rust - 不能借用 `*self` 作为可变的,因为 `self.history[..]` 也被借用为不可变的

rust - 如何从字符串生成元组?

c++ - 对由类型运算符创建的临时引用

c++ - 多个 std::string 临时对象导致相同的 c_str 指针

Rust 比较 Option<Vec<u8>> 和 Option<&[u8]>

rust - `if let` 如果中间值不运行析构函数

rust - 如何将 [u64;N] 转换为 [u8;8*N]?

rust - 为什么 "the temporary is part of an expression at the end of a block"是一个错误?

c++ - 返回对临时(内置类型)的引用

apache - apache tomcat 中的奇怪临时文件夹