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
String
用Target=str
实现了Deref
。
impl Deref for String {
type Target = str;
fn deref(&self) -> &str {
// [...]
}
}
得益于这种实现方式和强制Deref,&String
会在需要时自动转换为&str
不要滥用强制Deref
强制Deref是一个很强大的功能,但是可能会导致混乱。
自动类型转换会让代码更加难以阅读和理解。如果在T和U上都定义了同名的方法,那么将调用哪一个?
教程说,后面会讨论deref强制的“最安全”的用例:智能指针。
练习
这次的练习我感觉好像和Deref trait
关系不大?
让我们寻找一个String方法,可以去除字符串首尾的空格。这个方法肯定其他语言也有,C/C++和Java应该都有吧,不过我忘了,从来没太注意过。
好在查阅了Rust文档确实能找到,只要Ctrl + F
搜索white就行了,然后就找到了trim()方法
。直接用上就行了