我正在尝试通过将它与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();
如果临时值处于if
条件下,则根据reference,生命周期仅限于条件表达式。
// 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
语句的行为,因为它是由模式匹配借用的。
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>
,如果临时没有为整个匹配块生存,那么它就不会通过借来。
如果条件不遵循相同的规则,因为if条件中的最后一个函数调用不可能保存对任何东西的引用。他们必须评估一个普通的bool
。
看到: