impl 中的生命周期与 trait 中的方法不匹配

Chr*_*ith 5 lifetime rust

代码

Playground(Stable 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)
    }
}
Run Code Online (Sandbox Code Playgroud)

问题

我在get_valuefor的实现上遇到编译器错误RawBytes

error[E0195]: lifetime parameters or bounds on method `get_value` do not match the trait declaration
Run Code Online (Sandbox Code Playgroud)

我不明白问题是什么。两个定义之间的生命周期规范似乎相同。我如何编写get_valuefor 的实现RawBytes以使其有效?

我会认为从那时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 借来)。像u8这样可以直接返回的大小类型有一个AsSizedself 类型

也试过

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

我尝试简化 implget_value以直接命名切片;rust 然后说 impl forget_value完全丢失了。

fn get_value<'a>(&self, bytes: &'a [u8], arena: &'a Arena) -> Result<&'a [<u8 as AsSized<'a>>::AsSized]>
Run Code Online (Sandbox Code Playgroud)

这给出了相同的“生命周期参数......不匹配”错误。

Rei*_*iks 3

部分答案(我也被困住了:)

\n
\n

我不断删除代码,直到达到重现错误的最小示例:

\n
pub trait AsSized<\'a> {\n    type AsSized: Sized + \'a;\n}\n\npub trait Format<T>\nwhere\n    T: ?Sized,\n{\n    fn get_value<\'a>(&self, bytes: &\'a [u8])\n    where\n        T: AsSized<\'a>;\n}\n\nimpl Format<[u8]> for () {\n    fn get_value<\'a>(&self, bytes: &\'a [u8]) {\n        todo!()\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

现在很明显,在特征定义中,对生命周期有进一步的限制\'a:我们要求T: AsSized<\'a>,这就是导致错误的原因。该块上没有这样的子句impl,因此编译器不接受等效的生命周期。

\n

(我不确定它们是否实际上不兼容或者这是否是编译器的限制)

\n

所以我决定也添加where [u8]: AsSized<\'a>这个功能。impl为了让它编译,我还:

\n
    \n
  • 公开Arena(类型泄漏问题)
  • \n
  • 已从where [u8]: for<\'a> AsSized<\'a, AsSized=&\'a [u8]>impl这个 where 子句对我来说没有意义 \xe2\x80\x93 似乎没有意义,因为它不涉及泛型?我可能是错的。无论如何,它导致了一个奇怪的错误)
  • \n
  • 将函数体替换为todo!()
  • \n
\n

所以编译如下:

\n
fn main() {}\n\ntype Error = Box<dyn std::error::Error>;\ntype Result<R = ()> = std::result::Result<R, Error>;\n\npub struct Arena;\n\npub trait AsSized<\'a> {\n    type AsSized: Sized + \'a;\n}\nimpl<\'a, T: Sized + \'a> AsSized<\'a> for T {\n    type AsSized = Self;\n}\nimpl<\'a, T: AsSized<\'a>> AsSized<\'a> for [T] {\n    type AsSized = &\'a [T::AsSized];\n}\n\npub trait Format<T>: Send + Sync\nwhere\n    T: ?Sized,\n{\n    fn get_bytes<\'a>(&self, value: &\'a T, arena: &\'a Arena) -> Result<&\'a [u8]>;\n    fn get_value<\'a>(&self, bytes: &\'a [u8], arena: &\'a Arena) -> Result<T::AsSized>\n    where\n        T: AsSized<\'a>;\n}\n\nstruct RawBytes;\n\nimpl Format<[u8]> for RawBytes {\n    fn get_bytes<\'a>(&self, value: &\'a [u8], _arena: &\'a Arena) -> Result<&\'a [u8]> {\n        Ok(value)\n    }\n    fn get_value<\'a>(\n        &self,\n        bytes: &\'a [u8],\n        arena: &\'a Arena,\n    ) -> Result<<[u8] as AsSized<\'a>>::AsSized>\n    where\n        [u8]: AsSized<\'a>,\n    {\n        todo!()\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

不幸的是,当我把后背换成todo!()你的后Ok(bytes),它又坏了。编译器显然不知道它<[u8] as AsSized<\'a>>::AsSized&\'a [u8]. 那好吧。

\n
error[E0308]: mismatched types\n  --> src/main.rs:42:12\n   |\n42 |         Ok(bytes)\n   |         -- ^^^^^ expected associated type, found `&[u8]`\n   |         |\n   |         arguments to this enum variant are incorrect\n   |\n   = note: expected associated type `<[u8] as AsSized<\'a>>::AsSized`\n                    found reference `&\'a [u8]`\n   = 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`\n   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html\n
Run Code Online (Sandbox Code Playgroud)\n