Rust中Cons枚举map方法的所有权移动问题解惑
Rust中Cons枚举map方法的所有权移动问题
问题重现
首先是实现类列表结构的Cons枚举定义:
#[derive(Debug, PartialEq, Eq)] enum Cons<T: Clone> { Cons(T, Box<Cons<T>>), Null }
编写map方法时遇到问题,初始实现代码:
pub fn map<F,S>(&self, fun: F) -> Cons<S> where F: Fn(T) -> S, S: Clone { match self { &Cons::Null => Cons::Null, &Cons::Cons(ref head, ref tail) => Cons::new(fun(*head), tail.map(fun)), } }
编译器抛出错误:
error[E0507]: cannot move out of `*head` which is behind a shared reference --> src/lib.rs:50:56 | 50 | &Cons::Cons(ref head, ref tail) => Cons::new(fun(*head), tail.map(fun)), | ^^^^^ move occurs because `*head` has type `T`, which does not implement the `Copy` trait
使用clone修改后代码可以正常运行:
&Cons::Cons(ref head, ref tail) => Cons::new(fun(head.clone()), tail.map(fun)),
错误原因分析
这里的核心是共享引用的访问限制:
- map方法接收的是
&self——对Cons实例的共享不可变引用,这意味着我们只能读取内部数据,不能修改或转移它们的所有权。 match self里的ref head拿到的是T的共享引用(&T),而*head试图获取T的所有权。但因为T没有实现Copytrait,这个操作会尝试把T从共享引用后面“移出来”——Rust绝对不允许这么做,否则原Cons实例里的head会变成无效状态,破坏了共享引用的安全性规则。- 你定义的闭包
F要求接收T的所有权作为参数,这就和共享引用的限制直接冲突,所以编译器抛出了移动错误。
为什么clone能解决问题
head.clone()会基于共享引用创建一个T的全新副本,这个副本的所有权完全属于当前代码块。把副本传给闭包fun时,只是转移了副本的所有权,原Cons实例里的head数据丝毫不受影响,完全符合共享引用的使用规则,因此编译器不再报错。
内容的提问来源于stack exchange,提问作者k-tten
相关产品推荐
相关产品推荐

