25、Deref trait(解引用trait)

Deref trait(解引用trait)

上一节的练习很简单,我就没写

把代码:

impl Ticket {
    pub fn title(&self) -> &String {
        &self.title
    }
}

修改为:

impl Ticket {
    pub fn title(&self) -> &str {
        &self.title
    }
}

然后就可以通过测试了。

这里的教程说这里,只需要编译代码通过测试即可。但是会有一些其他问题的发生。

本不该工作,却工作了

回顾一些该函数的实际情况:

  • self.title是一个String
  • &self.title是一个&String
  • title方法的返回值是&str

诶,这么一看好像确实,编译器应该会出错的,该方法期待&String,但是却发现&str或类似的东西。相反,它却可以正常运行?(说实话,我还真没注意到这个问题…)

Deref摆平了这一切

Deref特性是 Rust 语言中所谓「自动解引用强制转换」(deref coercion)机制的核心实现。

该特性在标准库的 std::ops 模块中定义:

// 为便于理解,我们目前稍作简化。
// 后面会看到完整的定义。
pub trait Deref {
    type Target;

    fn deref(&self) -> &Self::Target;
}

其中,type Target 是一个关联类型(associated type)。它是一个占位符,用于表示在实现该 trait 时必须明确指定的具体类型。

强制Deref

通过为类型T实现deref<Target = U>,我们可以告诉编译器,&T和&U在某种程度上是可以互换的。

具体地讲,我们会遇到以下这些行为

  • 对T的引用隐式地转换为对U的引用(&T转换为&U)
  • 我们可以在&T上调用定义在U上的所有以&Self作为输入的方法

“对于解引用操作符还有一个东西,就是*,但是现在先不讨论(可以查看std的文档)”

字符串实现Deref

StringTarget=str实现了Deref

impl Deref for String {
    type Target = str;
    
    fn deref(&self) -> &str {
        // [...]
    }
}

得益于这种实现方式和强制Deref,&String会在需要时自动转换为&str

不要滥用强制Deref

强制Deref是一个很强大的功能,但是可能会导致混乱。

自动类型转换会让代码更加难以阅读和理解。如果在T和U上都定义了同名的方法,那么将调用哪一个?

教程说,后面会讨论deref强制的“最安全”的用例:智能指针。

练习

这次的练习我感觉好像和Deref trait关系不大?

image-20250910184340895

让我们寻找一个String方法,可以去除字符串首尾的空格。这个方法肯定其他语言也有,C/C++和Java应该都有吧,不过我忘了,从来没太注意过。

好在查阅了Rust文档确实能找到,只要Ctrl + F搜索white就行了,然后就找到了trim()方法。直接用上就行了

image-20250910184526314

阅读剩余
THE END