简体   繁体   English

为什么借用特征要求借用的类型作为参考?

[英]Why does the Borrow trait require the borrowed type to be a reference?

Imagine some event source, which produces events represented as an enum. 想象一下一些事件源,它产生表示为枚举的事件。 Of course, for best efficiency, this producer is zero-copy, ie it returns references to its internal buffers: 当然,为了获得最佳效率,此生产者是零拷贝,即它返回对其内部缓冲区的引用:

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

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

This is perfectly fine for consumers that don't require lookahead or backtracking, but sometimes there is a need to save some sequence of events. 这对于不需要前瞻或回溯的消费者来说非常好,但有时需要保存一些事件序列。 Thus, our Variant type becomes a generic: 因此,我们的Variant类型变为通用:

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

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

Here, we end up with two types with "owner-reference" relationship, which is similar to pairs Vec<T> - &[T] , String - &str . 在这里,我们最终得到两种具有“所有者 - 引用”关系的类型,它类似于对Vec<T> - &[T]String - &str Docs suggest builtin traits Borrow and ToOwned which provide just what is required except for a subtle nuance: 文档建议内置特征BorrowToOwned提供除了微妙的细微差别之外所需的内容:

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

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

Result of borrow is required to be a reference to something , which BorrowedVariant<'a> is obviously not. borrow结果必须是对某些东西引用 ,而BorrowedVariant<'a>显然不是。 Removing this requirement solves this problem (here, names are prefixed with alt to emphasize the fact this is an alternative interface): 删除此要求可以解决此问题(此处,名称以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;
}

This trait could then be implemented for standard types, eg Vec : 然后可以针对标准类型实现此特征,例如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()
    }
}

As well as for the Variant enum in question: 以及有问题的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()),
        }
    }
}

Finally, the questions: 最后,问题:

  1. Am I misusing the original Borrow / ToOwned concept? 我是否滥用了原始的Borrow / ToOwned概念? Should I use something else to achieve this? 我应该用别的东西来实现这个目标吗?
  2. If not, then what are the reasons why the current less-generic interface from std::borrow might have been preferred? 如果没有,那么为什么std::borrow当前不太通用的接口可能是首选的原因是什么?

This example on Rust playpen 这个例子在Rust游戏围栏上

Got some explanation on #rust IRC. 对#rust IRC有一些解释

From aturon : 来自aturon

the short answer is: we'd need higher-kinded types (HKT) to do better here; 简短的回答是:我们需要更高级别的(HKT)才能在这里做得更好; it should be possible to smoothly "upgrade" to HKT later on, though 不过,应该可以在以后顺利“升级”到HKT

(this is a pattern that's come up a few places in the standard library) (这是一种在标准库中出现的模式)

(lifting the lifetime to the trait level is a way of encoding HKT, but makes it significantly more awkward to use the trait) (将生命周期提升到特质水平是对HKT进行编码的一种方式,但使使用该特征更加尴尬)

From bluss : 来自布鲁斯

I like your question. 我喜欢你的问题。 That kind of lifetime in a trait hasn't been explored enough IMO but it also has a known bug in the borrow checker right now 这种特质的生命周期还没有被IMO充分探索过,但现在借用检查器中也存在一个已知的错误

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么解构借用的枚举需要取消引用其字段? - Why does destructuring a borrowed Enum require dereferencing its fields? 为什么在将变量移动到 scope 后 Rust 编译器错误“不能作为不可变借用,因为它也作为可变借用”? - Why does the Rust compiler error with "cannot borrow as immutable because it is also borrowed as mutable" after moving the variable into a scope? 为什么在泛型函数中对特征的引用必须实现`Sized`? - Why does a reference to a trait in a generic function have to implement `Sized`? 不能借用为可变的,因为它也被借用为不可变的 - Cannot borrow as mutable because it is also borrowed as immutable 为什么Rust不明白不再借用一个reference? - Why doesn't Rust understand that a reference is no longer borrowed? 类型特征:检查引用成员变量是否为静态 - Type trait: Check if reference member variable is static or not 为什么在分配REQUIRE垃圾收集时创建引用? - Why does the creation of a reference when assigning REQUIRE garbage collection? 为什么在某些特征方法调用中会导致&mut导致引用弱化? - Why does reference weakening from &mut occur in some trait method calls? Rust - 为借用特征指定生命周期参数 - Rust - Specifying a Lifetime Parameter for the Borrow Trait 错误:不能借用......作为不可变的,因为它也被借为可变的 - error: cannot borrow … as immutable because it is also borrowed as mutable
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM