我试图创建一个泛型特征,其中一个方法使用一个默认实现,该实现包装其余方法以减少样板.

这是一个最小的复制:

trait ReadFormat<'a, 'b: 'a, Arg: 'b, T: 'static>: Sized {
    fn new(c: &'a mut Cursor<'a>, arg: Arg) -> Self;
    fn into_format(self) -> SResult<T>;
    fn read(bytes: &'b [u8], arg: Arg) -> SResult<T> {
        let c = &mut Cursor::new(bytes);
        let r = Self::new(c, arg);
        let f = r.into_format();
        f
    }
}

我收到以下错误

61 | trait ReadFormat<'a, 'b: 'a, Arg: 'b, T: 'static>: Sized {
   |                  -- lifetime `'a` defined here
...
65 |         let c = &mut Cursor::new(bytes);
   |                      ^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
66 |         let r = Self::new(c, arg);
   |                 ----------------- argument requires that borrow lasts for `'a`
...
69 |     }
   |     - temporary value is freed at the end of this statement

我试过各种不同的人生组合,但都不管用.总的来说,我不明白当它被into_Format消耗,而T拥有它的所有数据时,它为什么期望self在读取返回后存活.

如果我将完全相同的代码复制粘贴到一个具体的实现中,并用Reader::New替换Self::New,它就会编译.

impl<'a, 'b: 'a> ReadFormat<'a, 'b, (), ()> for Reader<'a> {
    ..
    fn read(bytes: &'b [u8], arg: ()) -> SResult<()> {
        let c = &mut Cursor::new(bytes);
        let r = Reader::new(c, arg);
        let f = r.into_format();
        f
    }
}

推荐答案

我不明白为什么它希望赛尔夫在读完书后还能活着

它没有;问题是c条生命有多长.

new()的签名需要'a的引用,这是一个声明为on the trait的生存期参数.因此,对于特征的任何特定用法,如果调用new(),在停止使用特征实现之前,c引用必须有效.但是,cread()中的一个局部变量,这是特征实现的inside,所以它不会存在那么长时间.

下面是一个相同错误的非特征示例,但由于相同的原因而失败:

struct Cursor {}
struct Foo<'a> {
    c: &'a mut Cursor,
}

impl<'a> Foo<'a> {
    fn read() {
        let c = &mut Cursor {};
        let _ = Self { c };
    }
}

为了避免此问题,您必须

  • 在特征上没有任何生存期参数,或者
  • 不要把read()作为一个特征函数--这会让它与所涉及的生命周期有更灵活的关系.

你遇到的另一个问题是,&'a mut Cursor<'a>类型--或者更笼统地说,&'a mut Something<'a>--基本上总是错误的.对可变引用和引用的第contents个使用相同的生存期将创建两个超期约束:

  • &'a mut Cursor<'a>必须对'a有效(必须比'a更长),否则它不是&'a ....
  • 'a必须比Cursor<'a>活得久,否则Cursor可能会有悬念.

在两个地方使用相同生命周期 的结果是,Cursor变成了借来的for the rest of its existence,这可能不是你想要的.

解决方案是为引用和被引用对象使用不同的生存期.


把所有这些放在一起:

struct Cursor<'b>(&'b [u8]);
impl<'b> Cursor<'b> {
    fn new(bytes: &'b [u8]) -> Self {
        Self(bytes)
    }
}

trait ReadFormat<'cur, 'bytes, Arg, T>: Sized {
    fn new(c: &'cur mut Cursor<'bytes>, arg: Arg) -> Self;
    fn into_format(self) -> Result<T, ()>;
}

fn read<'b, R, Arg, T>(bytes: &'b [u8], arg: Arg) -> Result<T, ()>
where
    // for<'cur> means this trait can be used with ANY cursor lifetime
    R: for<'cur> ReadFormat<'cur, 'b, Arg, T>
{
    let c = &mut Cursor::new(bytes);
    let r = R::new(c, arg);
    r.into_format()
}

如果让ReadFormat::new()采用拥有的Cursor而不是&mut引用,则可以进一步简化操作;这将消除对游标生存期的higher-rank trait bound的需要,因为根本没有游标生存期.但或许这并不符合你的目标.


顺便提一句,以下是几条提示,供你下次提问或只是进行故障排除时参考:

  • 你的"最小复制"不是complete;它没有给出Cursor类型的定义.这在这里似乎并不重要,但它可以.
  • 在"…the Following Error"中,您go 掉了实际的主要错误消息--以error: ...开头的那一行.包括这条信息很重要,对read条信息来说更重要.以下几行中的信息应理解为主要信息之后的更多细节,而不是独立存在.

Rust相关问答推荐

有没有方法处理rust中嵌套的ok_or()?

如果LET;使用布尔表达式链接(&Q);

有没有办法在Rust中配置常量变量的值?

从Type::new()调用函数

可以为rust构建脚本编写单元测试吗?

为什么这个变量不需要是可变的?

在Rust中判断编译时是否无法访问

`tokio::pin` 如何改变变量的类型?

从Rust 的临时文件中创建引用是什么意思?

在不安全的 Rust 中存储对 struct 内部数据的静态引用是否合法?

为什么不能在 Rust 中声明静态或常量 std::path::Path 对象?

使用自定义 struct 收集 Vec

如何将 Rust 中的树状 struct 展平为 Vec<&mut ...>?

将 Futures 的生命周期特征绑定到 fn 参数

If let expression within .iter().any

Rust 中函数的类型同义词

当我不满足特征界限时会发生什么?

从函数返回 u32 的数组/切片

类型组的通用枚举

为什么 u64::trailing_zeros() 在无分支工作时生成分支程序集?