【问题标题】:Rust ownership - cannot move due to being "behind a shared reference"Rust 所有权 - 由于“在共享引用之后”而无法移动
【发布时间】:2026-01-15 08:25:01
【问题描述】:

我正在学习 Rust 并练习链接列表,因此我想找到一个最终不涉及 .clone() 的解决方案。

这是我能想到的最小的有用 MVP 代码 (Rust Playground):

#![allow(unused)]
fn main() {
    let v: Option<Box<ListNode>> = None;

    println!("{:?}", v);
    let result2 = get_nth_node(v, 3);
    println!("  --> {:?}", result2);
}

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct ListNode {
    pub val: i32,
    pub next: Option<Box<ListNode>>
}

fn get_nth_node(head: Option<Box<ListNode>>, n:usize) -> Option<Box<ListNode>> {
    if head.is_none() {
        return None;
    }

    let mut count = 1;
    let mut ptr: &Option<Box<ListNode>> = &head;
    while count < n {
        count += 1;
        match ptr {
            None                    => return None,
            Some(v) => ptr = &v.next
        }
    }
    return (*ptr);
}

这会在移动和借用时产生错误:

error[E0507]: cannot move out of `*ptr` which is behind a shared reference
  --> src/main.rs:30:12
   |
30 |     return (*ptr);
   |            ^^^^^^
   |            |
   |            move occurs because `*ptr` has type `std::option::Option<std::boxed::Box<ListNode>>`, which does not implement the `Copy` trait
   |            help: consider borrowing the `Option`'s content: `(*ptr).as_ref()`

我明白为什么将函数更改为返回 (*ptr).clone() 有效,但这似乎是多余的。

我的两个主要问题:

  1. *ptr 背后的共享引用具体是什么?
  2. 从概念上讲,在 Rust 中是否有更好的方法来处理它?

【问题讨论】:

  • 如果你还不知道,关于在 Rust 中实现链表的近乎强制性的阅读已经结束 here。 (剧透:很难让他们正确)
  • 如果我有更多的信誉,我会支持你的评论,@E_net4iscleaningup。谢谢指点。

标签: rust linked-list ownership


【解决方案1】:

*ptr 背后的共享引用具体是什么?

ptr 是共享(不可变)引用:

let mut ptr: &Option<Box<ListNode>> = &head;

*ptr 在该引用的后面。

从概念上讲,在 Rust 中是否有更好的方法来使用它?

好吧,您不能使用引用,因为您按值获取列表并因此使用它:

fn get_nth_node(mut head: Option<Box<ListNode>>, n:usize) -> Option<Box<ListNode>> {
    let mut count = 1;
    while count < n {
        count += 1;
        match head {
            None                    => return None,
            Some(v) => head = v.next
        }
    }
    return head;
}

或者,您可以使用 refs(这可能是一个更好的主意):


fn get_nth_node(mut head: Option<&ListNode>, n:usize) -> Option<&ListNode> {
    let mut count = 1;
    while count < n {
        count += 1;
        match head {
            None                    => return None,
            Some(v) => head = v.next.as_ref().map(Box::as_ref)
        }
    }
    head
}

【讨论】:

  • 很好的答案 - 谢谢。特别是围绕使用引用或全部不在函数范围内工作的主题。我确实很容易得到了第二个解决方案,但最终这个问题来自一次编程竞赛,迫使我在没有参考的情况下进行签名。