Appearance
20.5 自定义解引用
继续分析 Vec 的源码。Vec 是一个“动态数组”,它的行为应该尽量与默认的定长数组一致。语言内置的定长数组支持数组切片功能,可以使用一个 Slice 作为指向数组某个部分的“视图”。那我们也应该为 Vec 实现这样的功能。这种情况我们需要利用 Deref,代码如下:
rust
impl<T> ops::Deref for Vec<T> {
type Target = [T];
fn deref(&self) -> &[T] {
unsafe {
let p = self.buf.ptr();
assume(!p.is_null());
slice::from_raw_parts(p, self.len)
}
}
}
Target 类型是[T]
,这意味着*Vec<T>
的类型为[T]
,所以&*Vec<T>
的类型为&[T]
。
当碰到可以“隐式自动 deref”的场景时,&Vec<T>
类型如果不匹配,编译器就会继续尝试&*Vec<T>
,即&[T]
类型来匹配。所以,我们就可以在需要&[T]
类型的时候,直接使用&Vec<T>
。
Deref 在许多时候都很有用。因为 Deref 的存在,实现vec[..]
这样的功能很简单,因为编译器会帮我们实现类型自动转换:
rust
impl<T> ops::Index<ops::RangeFull> for Vec<T> {
type Output = [T];
#[inline]
fn index(&self, _index: ops::RangeFull) -> &[T] {
self
}
}
我们知道 self 的类型是&Vec<T>
,而函数定义的返回类型是&[T]
,因为有 Deref 的存在,编译器会帮我们做这个自动类型转换。
再比如索引 Index 功能,其内部实现方式就是先 deref 为原生数组类型,然后利用内置数组的 Index 功能实现:
rust
impl<T> Index<usize> for Vec<T> {
type Output = T;
#[inline]
fn index(&self, index: usize) -> &T {
// NB built-in indexing via `&[T]`
&(**self)[index]
}
}
读者看到(**self)
的时候不要惊慌,我们慢慢分析。self 类型是&Vec<T>
,因此*self
类型是Vec<T>
,**self
类型是[T]
。因此这句话的意思是:对[T]
执行 Index 操作后,再把引用返回。