集合是智能指针

描述

使用Dereftrait将集合视为智能指针,提供拥有 和借用的数据视图。

例子

use std::ops::Deref;

struct Vec<T> {
    data: RawVec<T>,
    //..
}

impl<T> Deref for Vec<T> {
    type Target = [T];

    fn deref(&self) -> &[T] {
        //..
    }
}

一个Vec<T>是一个拥有T的集合,一个切片(&[T])是一个借用T的集合。 为Vec实现Deref允许从&Vec<T>&[T]的隐式解引用,并在自动解引用搜索中包含这种关系。 你可能期望为Vec实现的大多数方法都是为切片实现的。

参见String&str

动机

所有权和借用是Rust语言的关键方面。 数据结构必须正确说明这些语义,以便提供良好的用户体验。 当实现一个拥有其数据的数据结构时,提供该数据的借用视图可以实现更灵活的API。

优势

大多数方法只为借用视图实现,然后它们隐含地对拥有视图可用。

让客户端在借用或拥有数据的所有权之间做出选择。

劣势

只有通过解引用才能使用的方法和trait在边界检查时不被考虑,所以使用这种模式的数据结构的泛型编程会变得很复杂(见BorrowAsReftrait等)。

讨论

智能指针和集合是类似的:一个智能指针指向一个对象,而一个集合指向许多对象。 从类型系统的角度来看,这两者之间没有什么区别。 如果访问每个数据的唯一途径是通过集合,并且集合负责删除数据(即使在共享所有权的情况下,某种借用视图可能是合适的),那么集合就拥有它的数据。 如果集合拥有它的数据,提供借用数据的视图通常是有用的,这样它就可以被多次引用了。

大多数智能指针(例如,Foo<T>)实现了Deref<Target=T>。 然而,集合通常会解引用到一个自定义的类型。 [T]str有一些语言支持,但在一般情况下,这是没有必要的。 Foo<T>可以实现Deref<Target=Bar<T>,其中Bar是一个动态大小的类型,&Bar<T>是对Foo<T>中数据的借用视图。

通常,有序集合为Range实现Index,以提供分片语法。目标是借用视图。

参见

反面模式:解引用多态性.

Deref trait 文档.

Latest commit 66d7e6c on 2 Oct 2021