【问题标题】:TryFrom<&[u8]> trait bound in traitTryFrom<&[u8]> 特征绑定在特征中
【发布时间】:2020-07-13 07:24:08
【问题描述】:

我正在尝试为从二进制数据(从磁盘读取)创建的一堆类型实现共同特征。大多数特征方法可以使用默认实现,并且只需要单独实现转换等。我想使用TryFrom&lt;&amp;[u8]&gt; trait 将二进制数据转换为我的类型,但我不知道如何表达(在 trait 的上下文中)&amp;[u8] 的生命周期以及从中创建的类型的值的生命周期是不相关的。这是问题的最小示例。

use std::convert::TryFrom;

struct Foo;

// Value of Foo can be created from &[u8] but it doesn't borrow anything.
impl TryFrom<&[u8]> for Foo {
    type Error = ();

    fn try_from(v: &[u8]) -> Result<Self, ()> {
        Ok(Foo)
    }
}

trait Bar<'a>
where
    Self: TryFrom<&'a [u8], Error = ()>, // `&` without an explicit lifetime name cannot be used here
{
    fn baz() -> Self {
        let vec = Vec::new();
        Self::try_from(&vec).unwrap() // ERROR: vec does not live long enough (nothing is borrowed)
    }
}

另一种解决方案是将转换作为特征方法,但使用常见的 std 特征会更好。有没有办法做到这一点? (或者我可以使用 const 泛型,但我不想依赖夜间编译器。)

【问题讨论】:

    标签: rust


    【解决方案1】:

    您想要的是“更高等级的特征界限”(HRTB,或简称为hearty boy)。它们看起来像这样:for&lt;'a&gt; T: 'a。这个例子只是意味着:“对于每个可能的生命周期'aT 必须......”。在你的情况下:

    trait Bar
    where
        Self: for<'a> TryFrom<&'a [u8], Error = ()>,
    

    您也可以直接将该要求指定为超级特征绑定而不是where 子句:

    trait Bar: for<'a> TryFrom<&'a [u8], Error = ()> { ... }
    

    是的,现在这只是意味着Bar 的所有实现者必须在所有 个可能的生命周期内实现TryFrom&lt;&amp;'a [u8], Error = ()&gt;。这就是你想要的。

    Working Playground

    【讨论】:

    • 谢谢,这正是我想要的。但是,我不确定直接指定超级特征绑定的优势是什么意思。我的印象是使用 where 子句在语义上是等效的(而且我认为 where 版本更易于阅读)。
    • @awdrt Mhhh,很有趣。我认为这会影响其他人对该特征的期望。但我试过了,我找不到where 和超级特征绑定之间的区别。所以我从我的回答中删除了这句话。也许我只是记错了:D
    • 在第一个示例中,trait Bar&lt;'a&gt; 应该没有生命周期。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-24
    • 1970-01-01
    • 2018-05-18
    • 1970-01-01
    • 2012-02-26
    • 2020-07-31
    • 1970-01-01
    相关资源
    最近更新 更多