我一直在解决一些 leetcode 问题,但遇到了一个我无法解释的问题。
#[derive(Debug)]
pub struct ListNode {
pub val: i32,
pub next: Option<Box<ListNode>>,
}
impl ListNode {
fn new(val: i32) -> Self {
ListNode { next: None, val }
}
}
fn main() {
let mut list = Some(Box::new(ListNode {
val: 1,
next: Some(Box::new(ListNode {
val: 2,
next: Some(Box::new(ListNode { val: 3, next: None })),
})),
}));
let mut tail = &mut list.as_mut().unwrap().next;
// This compiles fine
// while tail.is_some() {
// tail = &mut tail.as_mut().unwrap().next;
// }
// This compiles fine
// while let Some(ref mut node) = tail {
// tail = &mut node.next;
// }
// However this does not
while let Some(node) = tail.as_mut() {
tail = &mut node.next;
}
*tail = Some(Box::new(ListNode::new(4)));
println!("{:#?}", list);
}
Run Code Online (Sandbox Code Playgroud)
这是错误:
error[E0506]: cannot assign to `*tail` because it is borrowed
--> src/main.rs:39:5
|
35 | while let Some(node) = tail.as_mut() {
| ---- borrow of `*tail` occurs here
...
39 | *tail = Some(Box::new(ListNode::new(4)));
| ^^^^^
| |
| assignment to borrowed `*tail` occurs here
| borrow later used here
Run Code Online (Sandbox Code Playgroud)
为什么循环后tail仍然借用?while let Some() = xxx
这是由于thatwhile let ...和中的审查者 的交互作用,它是地点表达式上下文中的值表达式。tail.as_mut()while let
简而言之,为了让循环体while let能够访问绑定 ( node),编译器需要借用tail(在循环之前创建)、调用as_mut()、Option保留隐式临时借用Option(!),以及绑定值as_mut()返回到node;据编译器所知, 的生命周期node取决于Option,因为它是通过 漏斗的&'a mut tail -> as_mut(&'a mut self) -> &'a mut ListNode。
当您重新分配时tail = &mut node.next,这仍然是隐式生命周期的值'a,借用循环创建的原始临时值。
*tail当您在循环后分配给时,会发生冲突:原始 上有一个隐式借用Option,它用于调用as_mut()首先创建node然后然后分配tail,但现在您正在分配给 - 就编译器而言 -选项。Option但是在借用时您无法使其无效,因此会发生错误。
这就是为什么编译器指向borrow of *tail occurs here(注意取消引用)循环的审查位置while let,然后 - 令人困惑 - 指向*tail = Some(...)使用借用的点。
另外两个示例编译良好,因为在 scrutinee 中没有创建临时对象来执行方法调用Option。