You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust模式匹配不获取所有权使用值解决E0382报错

问题背景

我正在学习too-many-linked-lists教程,尝试实现一个简单链表,初始代码如下:

use std::mem;

struct Node{
    elem: i32,
    next : Link,
}

enum Link {
    Empty,
    More(Box<Node>),
}

pub struct List{
    head: Link,
}

impl List{
    pub fn pop_node(&mut self) -> Link{
        let node = mem::replace(&mut self.head, Link::Empty);
        match node {
            Link::More(nd) => {self.head= nd.next;}
            _ => ()
        };
        node
    }
}

pop_node函数的设计目标是返回链表的头节点,但上述代码无法通过编译,编译器报错提示访问nd时发生了变量node的移动。具体编译错误如下:

error[E0382]: use of partially moved value: `node`
  --> src/first.rs:34:9
   |
31 |             Link::More(nd) => {self.head= nd.next;}
   |                        -- value partially moved here
...
34 |         node
   |         ^^^^ value used here after partial move
   |
   = note: partial move occurs because value has type `Box<Node>`, which does not implement the `Copy` trait
help: borrow this field in the pattern to avoid moving `node.0`
   |
31 |             Link::More(ref nd) => {self.head= nd.next;}
   |                        +++

For more information about this error, try `rustc --explain E0382`.

尝试过解包Node结构体等方案都没有生效,需要解决该编译问题。

错误原因

模式匹配写Link::More(nd)时,会将枚举变体内部包裹的Box<Node>所有权移动到nd变量上,导致外层的node变量发生部分移动。Rust所有权规则禁止使用被部分移动的值,因此最后返回node时会触发E0382错误。
仅按照编译器提示加ref拿到不可变引用也无法通过编译:一方面nd.next的赋值操作需要修改节点内部值,另一方面直接移动nd.next同样会导致nd被部分移动,连带外层node结构不完整,依然违反所有权规则。

修复方案

在模式匹配中使用ref mut获取节点的可变引用,同时配合mem::replace取出next字段值,避免节点内部发生部分移动,修复后的可运行代码如下:

use std::mem;

struct Node{
    elem: i32,
    next : Link,
}

enum Link {
    Empty,
    More(Box<Node>),
}

pub struct List{
    head: Link,
}

impl List{
    pub fn pop_node(&mut self) -> Link{
        let mut node = mem::replace(&mut self.head, Link::Empty);
        match node {
            Link::More(ref mut nd) => {
                // 临时将当前节点的next替换为空,取出原next作为新的链表头
                self.head = mem::replace(&mut nd.next, Link::Empty);
            }
            _ => ()
        };
        node
    }
}

逻辑说明

  • ref mut nd的绑定方式只会拿到Box<Node>的可变引用,不会发生所有权转移,外层node始终持有完整所有权,可以正常作为返回值。
  • 用mem::replace将nd.next替换为Link::Empty,既可以取出原next值赋值给新的链表头,也不会把next从节点中移走导致节点结构被破坏,从根源上避免了部分移动问题。

内容的提问来源于stack exchange,提问作者Devil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 05:57:17