Deref 强制转换(deref coercions)是 Rust 在函数或方法传参上的一种便利。Deref 强制转换只能作用
于实现了 Deref trait 的类型。Deref 强制转换将这样一个类型的引用转换为另一个类型的引用。例如,
Deref 强制转换可以将 &String 转换为 &str,因为 String 实现了 Deref trait 因此可以返回 &str。当这
种特定类型的引用作为实参传递给和形参类型不同的函数或方法时,Deref 强制转换将自动发生。这时
会有一系列的 deref 方法被调用,把我们提供的类型转换成了参数所需的类型。
Deref 强制转换的加入使得 Rust 程序员编写函数和方法调用时无需增加过多显式使用 & 和 * 的引用和
解引用。这个功能也使得我们可以编写更多同时作用于引用或智能指针的代码。
作为展示 Deref 强制转换的实例,让我们使用示例 15-8 中定义的 MyBox,以及示例 15-10 中增加
的 Deref 实现。示例 15-11 展示了一个有着字符串 slice 参数的函数定义:
文件名: src∕main.rs
fn hello(name: &str) {
println!(“Hello, {}!”, name);
}
fn main() {}
hello 函数有着 &str 类型的参数 name
可以使用字符串 slice 作为参数调用 hello 函数,比如 hello (”Rust”);。Deref 强制转换使得用 MyBox
类型值的引用调用 hello 成为可能,如示例 15-12 所示:
文件名: src∕main.rs
use std::ops::Deref;
impl Deref for MyBox {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
struct MyBox(T);
impl MyBox {
fn new(x: T) -> MyBox {
MyBox(x)
}
}
fn hello(name: &str) {
println!(“Hello, {}!”, name);
}
fn main() {
let m = MyBox::new(String::from(“Rust”));
hello(&m);
}
示例 15-12:因为 Deref 强制转换,使用 MyBox 的引用调用 hello 是可行的
这里使用 &m 调用 hello 函数,其为 MyBox 值的引用。因为示例 15-10 中在 MyBox 上实
现了 Deref trait,Rust 可以通过 deref 调用将 &MyBox 变为 &String。标准库中提供了 String
上的 Deref 实现,其会返回字符串 slice,这可以在 Deref 的 API 文档中看到。Rust 再次调用 deref 将
&String 变为 &str,这就符合 hello 函数的定义了。
如果 Rust 没有实现 Deref 强制转换,为了使用 &MyBox 类型的值调用 hello,则不得不编写示
例 15-13 中的代码来代替示例 15-12:
文件名: src∕main.rs
use std::ops::Deref;
impl Deref for MyBox {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
struct MyBox(T);
impl MyBox {
fn new(x: T) -> MyBox {
MyBox(x)
}
}
fn hello(name: &str) {
println!(“Hello, {}!”, name);
}
fn main() {
let m = MyBox::new(String::from(“Rust”));
hello(&(*m)[…]);
}
示例 15-13:如果 Rust 没有 Deref 强制转换则必须编写的代码
(*m) 将 MyBox 解引用为 String。接着 & 和 […] 获取了整个 String 的字符串 slice 来匹配 hello
的签名。没有 Deref 强制转换所有这些符号混在一起将更难以读写和理解。Deref 强制转换使得 Rust 自
动的帮我们处理这些转换。
当所涉及到的类型定义了 Deref trait,Rust 会分析这些类型并使用任意多次 Deref::deref 调用以获得
匹配参数的类型。这些解析都发生在编译时,所以利用 Deref 强制转换并没有运行时损耗!