Skip to content

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 操作后,再把引用返回。

Released under the MIT License