【问题标题】:Why does the Borrow trait require the borrowed type to be a reference?为什么 Borrow trait 需要被借来的类型作为引用?
【发布时间】:2015-05-06 17:37:34
【问题描述】:

想象一些事件源,它产生表示为枚举的事件。当然,为了获得最佳效率,这个生产者是零拷贝的,即它返回对其内部缓冲区的引用:

enum Variant<'a> {
    Nothing,
    SomeInt(u64),
    SomeBytes(&'a [u8])
}

impl Producer {
    fn next(&'a mut self) -> Variant<'a> { ... }
}

这对于不需要前瞻或回溯的消费者来说非常好,但有时需要保存一些事件序列。因此,我们的 Variant 类型变成了泛型:

enum Variant<BytesT> {
    Nothing,
    SomeInt(u64),
    SomeBytes(BytesT)
}

type OwnedVariant = Variant<Vec<u8>>;
type BorrowedVariant<'a> = Variant<&'a [u8]>;

在这里,我们最终得到了两种具有“所有者-引用”关系的类型,类似于对Vec&lt;T&gt;-&amp;[T]String-&amp;str。文档建议内置特征 BorrowToOwned 提供除了细微差别之外的所需内容:

trait Borrow<Borrowed: ?Sized> {
    fn borrow(&self) -> &Borrowed;
    // this: -----------^
}

pub trait ToOwned {
    type Owned: Borrow<Self>;
    fn to_owned(&self) -> Self::Owned;
}

borrow 的结果必须是对某物的引用BorrowedVariant&lt;'a&gt; 显然不是。删除此要求可解决此问题(此处,名称以 alt 为前缀以强调这是一个替代接口这一事实):

trait AltBorrow<'a, AltBorrowed> {
    fn alt_borrow(&'a self) -> AltBorrowed;
}

trait AltToOwned<'a> {
    type AltOwned: AltBorrow<'a, Self>;
    fn alt_to_owned(&'a self) -> Self::AltOwned;
}

然后可以为标准类型实现此特征,例如Vec:

impl<'a, T> AltBorrow<'a, &'a [T]> for Vec<T> {
    fn alt_borrow(&'a self) -> &'a [T] {
        self.as_slice()
    }
}

impl<'a, T> AltToOwned<'a> for &'a [T]
    where T: Clone
{
    type AltOwned = Vec<T>;

    fn alt_to_owned(&'a self) -> Vec<T> {
        self.to_vec()
    }
}

以及有问题的Variant 枚举:

impl<'a> AltBorrow<'a, BorrowedVariant<'a>> for OwnedVariant {
    fn alt_borrow(&'a self) -> BorrowedVariant<'a> {
        match self {
            &Variant::Nothing => Variant::Nothing,
            &Variant::SomeInt(value) => Variant::SomeInt(value),
            &Variant::SomeBytes(ref value) => Variant::SomeBytes(value.alt_borrow()),
        }
    }
}

impl<'a> AltToOwned<'a> for BorrowedVariant<'a> {
    type AltOwned = OwnedVariant;

    fn alt_to_owned(&'a self) -> OwnedVariant {
        match self {
            &Variant::Nothing => Variant::Nothing,
            &Variant::SomeInt(value) => Variant::SomeInt(value),
            &Variant::SomeBytes(value) => Variant::SomeBytes(value.alt_to_owned()),
        }
    }
}

最后,问题:

  1. 我是否误用了原来的Borrow/ToOwned 概念?我应该使用其他东西来实现这一点吗?
  2. 如果不是,那么可能首选std::borrow 的当前不太通用的接口的原因是什么?

This example on Rust playpen

【问题讨论】:

    标签: reference rust traits


    【解决方案1】:

    在#rust IRC 上获得some explanation

    来自aturon

    简短的回答是:我们需要更高种类的类型 (HKT) 才能在这里做得更好;不过以后应该可以顺利“升级”到HKT了

    (这是标准库中一些地方出现的模式)

    (将生命周期提升到 trait 级别是一种编码 HKT 的方式,但使用 trait 会变得更加尴尬)

    来自bluss

    我喜欢你的问题。 IMO 对这种特征的生命周期还没有进行足够的探索 但它现在在借用检查器中也有一个已知错误

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-09-28
      • 2015-08-05
      相关资源
      最近更新 更多