方法链接中的Rust临时变量生存期

时间:2019-03-22 02:45:22

标签: rust

我试图通过将Rust与我更熟悉的C ++中的类似概念进行比较来学习Rust的生存期规则。大多数时候,我的直觉非常有效,我可以理解规则。但是,在以下情况下,我不确定我的理解是否正确。

在Rust中,临时值的生存期是语句的结尾,除非使用let将最后一个临时值绑定到名称。

struct A(u8);
struct B(u8);

impl A {
    fn get_b(&mut self) -> Option<B> {
        Some(B(self.0))
    }
}

fn a(v: u8) -> A {
    A(v)
}

// temporary A's lifetime is the end of the statement
// temporary B binds to a name so lives until the enclosing block
let b = a(1).get_b();

// temporary A's lifetime is the end of the statement
// temporary B's lifetime extends to the enclosing block,
// so that taking reference of temporary works similar as above
let b = &a(2).get_b();

根据reference,如果临时值处于if条件下,则生存期仅限于条件表达式。

// Both temporary A and temporary B drops before printing some
if a(3).get_b().unwrap().val <= 3 {
    println!("some");
}

现在要问的是:

如果将let置于if条件中,由于模式匹配,我们将绑定到临时值的内部。我希望let绑定的临时值可以扩展到封闭的块,而其他临时值的寿命也应该受if条件的限制。

(在这种情况下,实际上所有内容都被复制了,我想甚至可以删除临时B,但这是一个单独的问题。)

但是,两个临时对象的生存期都扩展到了封闭的if块。

// Both temporary A and temporary B's lifetime are extended to the end of the enclosing block,
// which is the if statement
if let Some(B(v @ 0...4)) = a(4).get_b() {
    println!("some {}", v);
}

这应该被认为是Rust中的不一致之处吗?还是我误会了,并且有一个统一的规则可以解释这种行为?

完整代码示例:

请注意Rust的输出是

some 4
Drop B 4
Drop A 4

而C ++的输出是

Drop A 4                                                                                                                                                                         
some 4                                                                                                                                                                           
Drop B 4

我已经阅读了Reddit thread和Rust issue,我认为它们非常相关,但是我仍然找不到适用于Rust中所有情况的一套明确的寿命规则。

更新:

我不清楚的是为什么关于if条件表达式的临时生存期规则适用于if let。我认为let Some(B(v @ 0...4)) = a(4).get_b()应该是条件表达式,因此临时A的生存期应该受此限制,而不是整个if语句受限制。

可以预期将临时B的生存期扩展到整个if语句的行为,因为这是模式匹配所借用的。

1 个答案:

答案 0 :(得分:4)

if let构造只是match构造的语法糖。 let Some(B(v @ 0...4)) = a(4).get_b()不是在正则表达式if中使用的条件,因为它不是以bool计算的表达式。给出您的示例:

if let Some(B(v @ 0...4)) = a(4).get_b() {
    println!("some {}", v);
}

它的行为与本示例完全相同。没有例外。在类型或借用检查器尚未运行之前,if let被重写为match

match a(4).get_b() {
    Some(B(v @ 0...4)) => {
        println!("some {}", v);
    }
    _ => {}
}

临时工的寿命与他们在比赛区的寿命一样长,因为有时他们会派上用场。就像如果您的最后一个函数是fn get_b(&mut self) -> Option<&B>,并且如果该临时项在整个match块中都不存在,那么它就不会传递rowck。

if条件不遵循相同的规则,因为if条件中的最后一个函数调用不可能持有对任何内容的引用。他们必须求出简单的bool