Bil*_*lly 8 coercion dereference rust
在阅读了 Rust 书中关于智能指针和内部可变性的部分后,作为个人练习,我尝试编写一个函数来遍历智能指针的链表并返回列表中的“最后一个”元素:
#[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),
}
}
Run Code Online (Sandbox Code Playgroud)
此代码导致以下错误:
| Nil | Cons(_, Nil) => list,
| ^^^ expected struct `std::rc::Rc`, found enum `List
Run Code Online (Sandbox Code Playgroud)
我能够通过使用“匹配保护”并明确取消对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),
}
}
Run Code Online (Sandbox Code Playgroud)
鉴于我对隐式取消引用和Deref
trait 实现的了解Rc
,我本以为我的第一次尝试会成功。为什么我必须在这个例子中明确取消引用?
Apl*_*123 10
首先,我们需要了解什么是取消引用强制。如果T
解引用U
并且x
是 type 的值T
,则:
*x
是 *Deref::deref(&x)
&T
可以被强制 &U
x.method()
将U
在方法解析期间检查类型。方法解析的工作原理是当您在类型上调用方法时,它首先通过向类型添加任何内容,然后添加&
,然后添加&mut
,然后取消引用来检查方法。因此,在确定要调用哪个方法时x.method()
,它会首先检查采用T
, then &T
, then &mut T
, then U
, then &U
, then 的方法&mut U
(在此处阅读更多内容)。这并不适用于运营商。因此,==
不会强制不同的类型,这就是您必须显式取消引用的原因。
但是如果我们确实使用了一个方法,比如.eq
在PartialEq
trait 中呢?事情变得有趣。以下代码失败:
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),
}
}
Run Code Online (Sandbox Code Playgroud)
但以下成功:
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),
}
}
Run Code Online (Sandbox Code Playgroud)
为什么是这样?我们来看第一个例子:
next_list
是 type &Rc<List>
,所以它开始搜索一个.eq
方法。它立即找到一个在PartialEq
实现中定义的Rc
with signature fn eq(&self, other: &Rc<List>)
。但是,在这种情况下other
是类型List
,不能强制为&Rc<List>
。
那为什么第二个工作呢?
Nil
是 type List
,所以它开始搜索一个.eq
方法。它找不到任何 for List
,所以它&List
接下来尝试,在那里它找到PartialEq
带有签名的派生实现fn eq(&self, other: &List)
。在这种情况下, other 是 type &Rc<List>
,&List
由于它的Deref
实现,可以强制转换为。这意味着所有类型检查都正确并且代码可以正常工作。
至于为什么你的第一次尝试没有成功,它似乎不是 Rust 中的一个功能,并且有一个可以追溯到 2017 的建议添加它。
归档时间: |
|
查看次数: |
415 次 |
最近记录: |