标准库提供了一个特殊的特性,[`Deref`](http://doc.rust-lang.org/nightly/std/ops/trait.Deref.html)。它一般用来重载`*`,解引用运算符:
~~~
use std::ops::Deref;
struct DerefExample<T> {
value: T,
}
impl<T> Deref for DerefExample<T> {
type Target = T;
fn deref(&self) -> &T {
&self.value
}
}
fn main() {
let x = DerefExample { value: 'a' };
assert_eq!('a', *x);
}
~~~
这对编写自定义指针类型很有用。然而,这里有一个与`Deref`相关的语言功能:“解引用强制多态(deref coercions)”。规则如下:如果你有一个`U`类型,和它的实现`Deref`,(那么)`&U`的值将会自动转换为`&T`。这是一个例子:
~~~
fn foo(s: &str) {
// borrow a string for a second
}
// String implements Deref<Target=str>
let owned = "Hello".to_string();
// therefore, this works:
foo(&owned);
~~~
在一个值的前面用`&`号获取它的引用。所以`owned`是一个`String`,`&owned`是一个`&String`,而因为`impl Deref for String`,`&String`将会转换为`&str`,而它是`foo()`需要的。
这就是了。这是Rust唯一一个为你进行一个自动转换的地方,不过它增加了很多灵活性。例如,`Rc`类型实现了`Deref`,所以这可以工作:
~~~
use std::rc::Rc;
fn foo(s: &str) {
// borrow a string for a second
}
// String implements Deref<Target=str>
let owned = "Hello".to_string();
let counted = Rc::new(owned);
// therefore, this works:
foo(&counted);
~~~
我们所做的一切就是把我们的`String`封装到了一个`Rc`里。不过现在我们可以传递`Rc`给任何我们有一个`String`的地方。`foo`的签名并无变化,不过它对这两个类型都能正常工作。这个例子有两个转换:`Rc`转换为`String`接着是`String`转换为`&str`。只要类型匹配Rust将可以做任意多次这样的转换。
标准库提供的另一个非常通用的实现是:
~~~
fn foo(s: &[i32]) {
// borrow a slice for a second
}
// Vec<T> implements Deref<Target=[T]>
let owned = vec![1, 2, 3];
foo(&owned);
~~~
向量可以`Deref`为一个片段。
## `Deref`和方法调用
当调用一个方法时`Deref`也会出现。换句话说,这两个(应该是`T`和`&T`)在Rust中是一样的:
~~~
struct Foo;
impl Foo {
fn foo(&self) { println!("Foo"); }
}
let f = Foo;
f.foo();
~~~
即便`f`不是一个引用,而`foo`获取`&self`,这也是可以工作的。因为这些都是一样的:
~~~
f.foo();
(&f).foo();
(&&f).foo();
(&&&&&&&&f).foo();
~~~
一个`&&&&&&&&&&&&&&&&Foo`类型的值仍然可以调用`Foo`定义的方法,因为编译器会插入足够多的`*`来使类型正确。而正因为它插入`*`,它用了`Deref`。
- 前言
- 1.介绍
- 2.准备
- 2.1.安装Rust
- 2.2.Hello, world!
- 2.3.Hello, Cargo!
- 3.学习Rust
- 3.1.猜猜看
- 3.2.哲学家就餐问题
- 3.3.其它语言中的Rust
- 4.高效Rust
- 4.1.栈和堆
- 4.2.测试
- 4.3.条件编译
- 4.4.文档
- 4.5.迭代器
- 4.6.并发
- 4.7.错误处理
- 4.8.外部语言接口
- 4.9.Borrow 和 AsRef
- 4.10.发布途径
- 5.语法和语义
- 5.1.变量绑定
- 5.2.函数
- 5.3.原生类型
- 5.4.注释
- 5.5.If语句
- 5.6.for循环
- 5.7.while循环
- 5.8.所有权
- 5.9.引用和借用
- 5.10.生命周期
- 5.11.可变性
- 5.12.结构体
- 5.13.枚举
- 5.14.匹配
- 5.15.模式
- 5.16.方法语法
- 5.17.Vectors
- 5.18.字符串
- 5.19.泛型
- 5.20.Traits
- 5.21.Drop
- 5.22.if let
- 5.23.trait对象
- 5.24.闭包
- 5.25.通用函数调用语法
- 5.26.包装箱和模块
- 5.27.`const`和`static`
- 5.28.属性
- 5.29.`type`别名
- 5.30.类型转换
- 5.31.关联类型
- 5.32.不定长类型
- 5.33.运算符和重载
- 5.34.`Deref`强制多态
- 5.35.宏
- 5.36.裸指针
- 6.Rust开发版
- 6.1.编译器插件
- 6.2.内联汇编
- 6.3.不使用标准库
- 6.4.固有功能
- 6.5.语言项
- 6.6.链接参数
- 6.7.基准测试
- 6.8.装箱语法和模式
- 6.9.切片模式
- 6.10.关联常量
- 7.词汇表
- 8.学院派研究
- 勘误