为什么 Rust 的临时值有时是引用的,有时不是?

Why are temporary values of Rust sometimes referential and sometimes not?

提问人:artzok 提问时间:5/30/2023 更新时间:5/30/2023 访问量:120

问:

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

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()

临时生锈

评论

0赞 Sven Marnach 5/30/2023
相关新闻: 为什么借临时房是合法的?

答:

3赞 Masklinn 5/30/2023 #1

s1 和 s2 有什么区别?

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

a = &get_i32();没有,因为 TLE 仅适用于 .let

let s2 = String::from("hello world").as_str();也没有,因为临时的生命周期被延长到语句的末尾,所以链本质上编译为块中的一系列调用,例如:

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"),
    }

整体是一个单一的语句,所以临时的一直存在到它的结束,这意味着我们可以得到对内部和外部值的引用,并使用一个我们从未在任何地方绑定的值(这是无稽之谈的代码,但它显示了原理,这是我想到的第一件事)。matchOption<String>&Option<&str>

但是,在某些情况下,如果尝试借入,然后将原始值移动到其中一个分支中,则会导致问题。这在非词法生存期(和借用检查)中已经不那么常见了,但它仍然不时发生。match

评论

0赞 artzok 5/30/2023
谢谢。根据你的回答,我明白原因。