在实现中的生命周期与trait中的方法不匹配

12

代码

示例代码(稳定版Rust 1.45.0,2018版)无需外部库。

type Error = Box<dyn std::error::Error>;
type Result<R=()> = std::result::Result<R, Error>;

struct Arena;

pub trait AsSized<'a> {
    type AsSized: Sized + 'a;
}
impl<'a, T: Sized + 'a> AsSized<'a> for T {
    type AsSized = Self;
}
impl<'a, T: AsSized<'a>> AsSized<'a> for [T] {
    type AsSized = &'a [T::AsSized];
}

pub trait Format<T>: Send + Sync
where T: ?Sized
{
    fn get_bytes<'a>(&self, value: &'a T, arena: &'a Arena) -> Result<&'a [u8]>;
    fn get_value<'a>(&self, bytes: &'a [u8], arena: &'a Arena) -> Result<T::AsSized>
    where T: AsSized<'a>;
}

struct RawBytes;

impl Format<[u8]> for RawBytes
where [u8]: for<'a> AsSized<'a, AsSized=&'a [u8]>
{
    fn get_bytes<'a>(&self, value: &'a [u8], _arena: &'a Arena) -> Result<&'a [u8]> {
        Ok(value)
    }
    fn get_value<'a>(&self, bytes: &'a [u8], arena: &'a Arena) -> Result<<[u8] as AsSized<'a>>::AsSized> {
        Ok(bytes)
    }
}

问题

我在RawBytesget_value实现中遇到了编译错误:

error[E0195]: lifetime parameters or bounds on method `get_value` do not match the trait declaration

我不理解问题出在哪里。两个定义之间的生命周期规范似乎是相同的。那么我应该如何编写RawBytesget_value的实现,以使其正常工作?

我认为由于u8: Sized,所以<u8 as AsSized<'a>>::AsSized = u8,然后<[u8] as AsSized<'a>>::AsSized = &'a [u8],但似乎情况并非如此?

背景

Format使用基于arena的分配器将字节片转换为复杂类型,并从中进行转换。我计划为各种Serde格式编写适配器。 RawBytes是一个针对字节片的Format的微不足道的实现,它只返回原始片。

Format的两种方法都允许返回从输入值借用的值。格式本身可以在线程之间共享,因此self的寿命与返回值的寿命无关。

AsSized的目的是允许直接使用动态大小的类型,例如str[u8],但由于动态大小的类型无法直接返回,AsSized为任何类型提供了一个大小等效的类型;动态大小的类型返回指向DST的引用(从arena借用)。可以直接返回的有大小的类型,其AsSized类型为self。

还尝试过

fn get_value<'a>(&self, bytes: &'a [u8], arena: &'a Arena) -> Result<'a [u8]>

我尝试将impl的get_value简化为直接命名切片;然后Rust表示get_value的实现完全丢失。
fn get_value<'a>(&self, bytes: &'a [u8], arena: &'a Arena) -> Result<&'a [<u8 as AsSized<'a>>::AsSized]>

这会产生相同的“lifetime parameters... do not match”错误。


很难回答你的问题,因为它没有包含一个 [MRE]。我们无法确定代码中存在哪些 crates (及其版本)、类型、traits、fields 等信息。在以后的操作中,如果可能的话,请试着在Rust Playground上重现您的错误,否则请在全新的 Cargo 项目中编辑您的问题以包括额外的信息。有一些Rust-specific MRE提示,您可以使用这些提示来减少要发布在此处的原始代码。谢谢! - mcarton
谢谢你的提示!我不知道有这方面的指南,应该检查一下标签。我会编辑问题的。 - Chris Smith
1
我添加了一个游乐场链接,可以重现我遇到的完全相同的错误,并添加了有关我使用的 Rust 版本的注释。 - Chris Smith
1个回答

3

部分答案(我也遇到了困难:)


我一直在删除代码,直到我达到了这个能够重现错误的最小示例:

pub trait AsSized<'a> {
    type AsSized: Sized + 'a;
}

pub trait Format<T>
where
    T: ?Sized,
{
    fn get_value<'a>(&self, bytes: &'a [u8])
    where
        T: AsSized<'a>;
}

impl Format<[u8]> for () {
    fn get_value<'a>(&self, bytes: &'a [u8]) {
        todo!()
    }
}

现在显然,在trait定义中,对于'a生命周期还有进一步的限制:我们要求>,这就是导致错误的原因。你在impl块中没有这样的子句,因此编译器不接受这些生命周期等价。
(我不确定它们是否真的不兼容,还是编译器的限制)
所以我决定在impl函数中也添加where [u8]: AsSized<'a>。为了使其编译,我还:
- 将Arena公开(类型泄漏问题) - 从impl中删除where [u8]: for<'a> AsSized<'a, AsSized=&'a [u8]>(这个where子句对我来说毫无意义——它似乎没有任何意义,因为它不涉及通用?我可能错了。反正它引起了一个奇怪的错误) - 用todo!()替换函数体
所以这个可以编译:
fn main() {}

type Error = Box<dyn std::error::Error>;
type Result<R = ()> = std::result::Result<R, Error>;

pub struct Arena;

pub trait AsSized<'a> {
    type AsSized: Sized + 'a;
}
impl<'a, T: Sized + 'a> AsSized<'a> for T {
    type AsSized = Self;
}
impl<'a, T: AsSized<'a>> AsSized<'a> for [T] {
    type AsSized = &'a [T::AsSized];
}

pub trait Format<T>: Send + Sync
where
    T: ?Sized,
{
    fn get_bytes<'a>(&self, value: &'a T, arena: &'a Arena) -> Result<&'a [u8]>;
    fn get_value<'a>(&self, bytes: &'a [u8], arena: &'a Arena) -> Result<T::AsSized>
    where
        T: AsSized<'a>;
}

struct RawBytes;

impl Format<[u8]> for RawBytes {
    fn get_bytes<'a>(&self, value: &'a [u8], _arena: &'a Arena) -> Result<&'a [u8]> {
        Ok(value)
    }
    fn get_value<'a>(
        &self,
        bytes: &'a [u8],
        arena: &'a Arena,
    ) -> Result<<[u8] as AsSized<'a>>::AsSized>
    where
        [u8]: AsSized<'a>,
    {
        todo!()
    }
}

很遗憾,一旦我用你的Ok(bytes)替换回todo!(),它又出问题了。编译器显然不知道<[u8] as AsSized<'a>>::AsSized&'a [u8]是相同的。哎呀。

error[E0308]: mismatched types
  --> src/main.rs:42:12
   |
42 |         Ok(bytes)
   |         -- ^^^^^ expected associated type, found `&[u8]`
   |         |
   |         arguments to this enum variant are incorrect
   |
   = note: expected associated type `<[u8] as AsSized<'a>>::AsSized`
                    found reference `&'a [u8]`
   = help: consider constraining the associated type `<[u8] as AsSized<'a>>::AsSized` to `&'a [u8]` or calling a method that returns `<[u8] as AsSized<'a>>::AsSized`
   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接