rust - 为什么 Rust 不在匹配模式中执行隐式 deref 强制?

标签 rust dereference coercion

在阅读了关于 Smart Pointers and Interior mutability 的 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),
    }
}
此代码导致以下错误:
   |         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 的特征实现,我本来希望我第一次尝试工作。为什么我必须在这个例子中明确取消引用?

最佳答案

首先,我们需要了解什么是取消引用强制。如 T取消引用 Ux是类型 T 的值, 然后:

  • *x*Deref::deref(&x)
  • &T可以强制到&U
  • x.method()将检查类型 U在方法解析期间。

  • 方法解析的工作原理是,当您在类型上调用方法时,它首先通过向类型添加任何内容来检查方法,然后添加 & ,然后添加 &mut ,然后取消引用。因此,在确定调用哪个方法时 x.method() ,它会首先检查一个接受 T 的方法,然后 &T ,然后 &mut T ,然后 U ,然后 &U ,然后 &mut U ( read more here )。此 适用于运营商。因此,==不会强制不同的类型,这就是您必须明确取消引用的原因。
    但是如果我们确实使用了一个方法,比如 .eqPartialEq特征?事情变得有趣。以下代码失败:
    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方法。它立即找到在 PartialEq 中定义的一个Rc 的实现带签名fn eq(&self, other: &Rc<List>) .然而,other类型为 List在这种情况下,不能强制为 &Rc<List> .
    那为什么第二个工作呢?Nil类型为 List ,所以它开始搜索 .eq方法。找不到 List 的任何内容,所以它会尝试 &List接下来,它找到派生的 PartialEq带签名的实现 fn eq(&self, other: &List) .在这种情况下,other 的类型为 &Rc<List> ,可以强制为 &List因为它的 Deref执行。这意味着所有类型检查都正确并且代码可以正常工作。
    至于为什么你的第一次尝试没有成功,它似乎不是 Rust 的一个特性,还有 a proposal to add it dating back to 2017 .

    关于rust - 为什么 Rust 不在匹配模式中执行隐式 deref 强制?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62851229/

    相关文章:

    rust - 通用特征实现错误

    pagination - Rust:BTreeMap 相等性+不等性范围查询

    rust - 如何重用范围来获取数组的一部分?

    pointers - 为什么打印指针与打印取消引用的指针打印相同的内容?

    ruby - 在 Ruby 中,coerce() 是如何工作的?

    javascript - 字符串强制转换为 bool 值

    rust - 如何同时运行包含借来的TcpStream的 future ?

    c++ - 重新分配指针给出错误

    function - 函数名前面的解引用运算符有什么作用?

    oracle - 对函数调用(堆栈框架)中的类型强制感到困惑