为啥 Rust 不在匹配模式中执行隐式取消引用强制?
Posted
技术标签:
【中文标题】为啥 Rust 不在匹配模式中执行隐式取消引用强制?【英文标题】:Why does Rust not perform implicit deref coercion in match patterns?为什么 Rust 不在匹配模式中执行隐式取消引用强制? 【发布时间】:2020-11-01 04:41:16 【问题描述】:阅读 Rust 书中Smart Pointers and Interior mutability 上的部分后,作为个人练习,我尝试编写一个函数,该函数将遍历智能指针的链表并返回列表中的“最后一个”元素:
#[derive(Debug, PartialEq)]
enum List
Cons(Rc<RefCell<i32>>, Rc<List>),
Nil,
use crate::List::Cons, Nil;
fn get_last(list: &List) -> &List
match list
Nil | Cons(_, Nil) => list,
Cons(_, next_list) => get_last(next_list),
此代码导致以下错误:
| Nil | Cons(_, Nil) => list,
| ^^^ expected struct `std::rc::Rc`, found enum `List
我能够通过使用“匹配守卫”并明确取消对 Cons(_, x)
模式的引用来使其工作:
fn get_last(list: &List) -> &List
match list
Nil => list,
Cons(_, next_list) if **next_list == Nil => list,
Cons(_, next_list) => get_last(next_list),
鉴于我对隐式取消引用和Deref
特征实现Rc
的了解,我预计我的第一次尝试会奏效。为什么我必须在此示例中显式取消引用?
【问题讨论】:
【参考方案1】:首先,我们需要了解 deref coercion 是什么。如果T
引用U
并且x
是T
类型的值,则:
*x
是 *Deref::deref(&x)
&T
可以强制转换为 &U
x.method()
将在方法解析期间检查类型 U
。
方法解析的工作原理是,当您在类型上调用方法时,它首先通过向类型中添加任何内容来检查方法,然后添加&
,然后添加&mut
,然后解除引用。因此,在确定调用 x.method()
的方法时,它会首先检查一个使用 T
的方法,然后是 &T
,然后是 &mut T
,然后是 U
,然后是 &U
,然后是 @ 987654341@ (read more here)。这不适用于运营商。因此,==
不会强制转换不同的类型,这就是您必须显式取消引用的原因。
但是如果我们确实在PartialEq
trait 中使用了.eq
之类的方法呢?事情变得有趣起来。以下代码失败:
fn get_last(list: &List) -> &List
match list
Nil => list,
Cons(_, next_list) if next_list.eq(Nil) => list,
Cons(_, next_list) => get_last(next_list),
但以下成功:
fn get_last(list: &List) -> &List
match list
Nil => list,
// notice how it's Nil.eq and not next_list.eq
Cons(_, next_list) if Nil.eq(next_list) => list,
Cons(_, next_list) => get_last(next_list),
这是为什么?我们来看第一个例子:
next_list
是&Rc<List>
类型,因此它开始搜索.eq
方法。它立即找到在Rc
的PartialEq
实现中定义的签名fn eq(&self, other: &Rc<List>)
。但是,other
在这种情况下属于List
类型,不能强制转换为&Rc<List>
。
那么为什么第二个工作?
Nil
是 List
类型,因此它开始搜索 .eq
方法。它找不到List
的任何内容,因此它接下来尝试&List
,在那里它找到了带有签名fn eq(&self, other: &List)
的派生PartialEq
实现。在这种情况下, other 是&Rc<List>
类型,由于其Deref
实现,它可以被强制转换为&List
。这意味着所有的类型检查都正确并且代码可以正常工作。
至于为什么你的第一次尝试没有成功,它似乎不是 rust 的一个功能,还有a proposal to add it dating back to 2017。
【讨论】:
以上是关于为啥 Rust 不在匹配模式中执行隐式取消引用强制?的主要内容,如果未能解决你的问题,请参考以下文章