对使用具有生命周期的 trait 作为泛型参数约束感到困惑 [英] Confused about using trait with lifetime as generic parameter constraint

查看:36
本文介绍了对使用具有生命周期的 trait 作为泛型参数约束感到困惑的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试制作某种解码器,它能够在不实际复制内存的情况下反序列化条目,只需将值映射到某些内存区域即可.这就是我目前设法做的(简化为测试用例):

I am trying to make some kind of decoder, that will be able to deserialize entries without actually copying memory, just by mapping values to some memory regions. That is what I currently managed to do (simplified for testcase):

#![allow(unstable)]

trait CastAbility: Sized { }
impl CastAbility for u64 { }
impl CastAbility for u32 { }
impl CastAbility for u16 { }
impl CastAbility for u8 { }

trait Cast {
    fn cast<'a>(mem: &'a [u8]) -> Result<&'a Self, String>;
}

impl<T> Cast for T where T: CastAbility {
    fn cast<'a>(mem: &'a [u8]) -> Result<&'a T, String> {
        if mem.len() != std::mem::size_of::<T>() { 
            Err("invalid size".to_string())
        } else {
            Ok(unsafe { std::mem::transmute(mem.as_ptr()) })
        }
    }
}

impl Cast for str {
    fn cast<'a>(mem: &'a [u8]) -> Result<&'a str, String> {
        Ok(unsafe { std::mem::transmute(std::raw::Slice { data: mem.as_ptr(), len: mem.len() }) })
    }
}

trait Read<'a> {
    fn read(mem: &'a [u8]) -> Result<Self, String>;
}

#[derive(Show, PartialEq)]
struct U8AndStr<'a> {
    value_u8: &'a u8,
    value_str: &'a str,
}

impl<'a> Read<'a> for U8AndStr<'a> {
    fn read(mem: &'a [u8]) -> Result<U8AndStr, String> {
        Ok(U8AndStr {
            value_u8: try!(Cast::cast(mem.slice(0, 1))),
            value_str: try!(Cast::cast(mem.slice(1, mem.len()))),
        })
    }
}

fn main() {
    let mem: &[u8] = &[0x01, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37];
    let value: U8AndStr = Read::read(mem).unwrap();

    println!("value: {:?}", value);
}

围栏

事实上它可以编译甚至可以工作,但现在我无法理解如何使用我的 Read 特性作为通用参数.例如,假设我想将一个值与某个内存区域的解码结果进行比较:

In fact it compiles and even works, but now I cannot understand how to use my Read trait as generic parameter. For example, suppose I want to compare a value to a decoded result of some memory area:

fn compare_to_smth<'a, T>(value: &'a T) -> bool where T: PartialEq+Read<'a> {
    let mem: &[u8] = &[0x01, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37];
    let smth_value: T = Read::read(mem).unwrap();
    smth_value == *value
}

fn main() {
    let value = U8AndStr { value_u8: &1, value_str: "01234567" };
    assert!(compare_to_smth(&value));
}

它因借来的值活得不够长"而失败,我能猜到原因:因为 mem 生命周期是函数体,而不是 'a,因为我确实在输入参数的签名中指定.所以我尝试使用第二个生命周期参数,如下所示:

It fails with "borrowed value does not live long enough", and I can guess why: because mem lifetime is the function body, not 'a, as I did specify in signature for input parameter. So I tried to use second lifetime paramater as shown:

fn compare_to_smth<'a, 'b, T>(value: &'a T) -> bool where T: PartialEq+Read<'b> {

但由于明显的原因,它也不起作用.所以我真的不明白如何在不从外部传递内存块的情况下使 compare_to_smth 工作.有什么解决方案,或者我应该以某种方式重构代码?

But it also didn't work for obvious reason. So I really don't understand how to make compare_to_smth work without passing memory chunk from outside. Is there any solution, or I should refactor the code somehow?

推荐答案

不幸的是,您想要做的事情目前在 Rust 中无法表达.

Unfortunately, what you want to do is inexpressible in Rust at the moment.

实际工作的 Read trait 的签名如下(在伪 Rust 中):

The signature of Read trait that actually would work is as follows (in pseudo-Rust):

trait<'r> Read for Self<'r> {
    fn read<'a>(mem: &'a [u8]) -> Result<Self<'a>, String>;  // '
}

也就是说,Self 在它的生命周期参数中必须是一个更高级的类型.这需要支持更高级的类型,这是 Rust 社区非常需要但尚未实现的功能.

That is, Self must be a higher-kinded type in its lifetime parameter. This requires support for higher-kinded types, which is a very desired feature in the Rust community but which is still yet to be implemented.

原始签名的问题:

trait Read<'a> {
    fn read(mem: &'a [u8]) -> Result<Self, String>;
}

'a 是特征的参数.当这个 trait 被用作 trait bound 时:

is that 'a is a parameter to the trait. When this trait is used as a trait bound:

fn compare_to_smth<'a, T>(value: &T) -> bool where T: PartialEq+Read<'a>

这意味着该函数的调用者选择了实际的生命周期参数.例如,调用者可以选择'static:

it means that the caller of this function chooses the actual lifetime parameter. For example, the caller may choose 'static:

fn compare_to_smth<T>(value: &T) -> bool where T: PartialEq+Read<'static>

然而,该函数使用了生命周期不是'static&[u8].

However, the function uses &[u8] whose lifetime is not 'static.

事实上,由于方差,这个具体的例子可能并不完全正确(我想这个生命周期在这里是 'static 是合理的,但是生命周期本身的方差有点令人困惑,所以我不太确定),但总体思路是一样的:为了使其工作,Read::read 方法在其参数和结果的生命周期中必须是多态的,但是你还不能写这样的签名.

In fact, this concrete example may be not exactly correct due to variance (I imagine it would be sound for this lifetime to be 'static here, but variance of lifetimes itself is somewhat confusing, so I'm not really sure), but nevertheless the general idea is the same: in order for this to work the Read::read method must be polymorphic in the lifetime of its argument and result, but you can't write such signature yet.

这篇关于对使用具有生命周期的 trait 作为泛型参数约束感到困惑的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆