以下代码示例是我遇到的问题的缩小版本.
trait Offset: Default {}
trait Reader {
type Offset: Offset;
}
impl Offset for usize {}
impl<'a> Reader for &'a [u8] {
type Offset = usize;
}
// OK
// struct Header<R: Reader>(R, usize);
// Bad
struct Header<R: Reader>(R, R::Offset);
impl <R: Reader<Offset=usize>> Header<R> {
fn new(r: R) -> Self {
Header(r, 0)
}
}
fn test<R: Reader>(_: Header<R>, _: Header<R>) {}
fn main() {
let buf1 = [0u8];
let slice1 = &buf1[..];
let header1 = Header::new(slice1);
let buf2 = [0u8];
let slice2 = &buf2[..];
let header2 = Header::new(slice2);
test(header1, header2);
}
Run Code Online (Sandbox Code Playgroud)
我目前使用代码usize而不是Offset相关的类型.我正在尝试概括我的代码,以便它可以与其他类型的偏移一起使用.但是,添加此关联类型会导致许多现有代码停止编译,并出现以下错误:
error[E0597]: `buf2` does not live long enough
--> src/main.rs:37:1
|
33 | let slice2 = &buf2[..];
| ---- borrow occurs here
...
37 | }
| ^ `buf2` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are created
Run Code Online (Sandbox Code Playgroud)
颠倒这个例子的顺序header1并buf2解决问题,但我不想在任何地方(也可能无法)进行此更改,我不明白为什么这是一个问题.
差异是问题的原因.
struct Header<R: Reader>(R, usize);,Header<R>是协变 wrt R.struct Header<R: Reader>(R, R::Offset);,Header<R>是不变的 wrt R.子类型是生命周期的安全转换.例如,&'static [u8]可以转换为&'a [u8].
方差描述了如何将子类型提升到复杂类型.例如,如果Header<_>是协变且R是子类型S,Header<R>则是子类型Header<S>.对于不变结构,情况并非如此.
在当前的Rust中,traits总是不变的,因为在当前语法中无法推断或指定trait方差.同样的限制适用于预计的类型,如R::Offset.
在你的代码,因为Header是不变的,Header<&'a [u8]>不能upcasted到Header<&'b [u8]>即使'a: 'b.由于fn test需要两个参数相同的类型,则编译器需要相同的寿命slice1和slice2.
一种可能的临时解决方案是在fn test可行的情况下概括签名.
fn test<R: Reader, S: Reader>(_: Header<R>, _: Header<S>) {}
Run Code Online (Sandbox Code Playgroud)
另一种解决方案是以Header某种方式使协变.
Header如果type Offset已经'static绑定,也许可以安全地假设是协变的,但是当前的编译器不会做这样一个聪明的推理.
也许你可以把生命时间作为一个参数来分解Header.这恢复了协方差.
trait Offset: Default {}
trait Reader {
type Offset: Offset;
}
impl Offset for usize {}
impl Reader for [u8] {
type Offset = usize;
}
struct Header<'a, R: Reader + ?Sized + 'a>(&'a R, R::Offset);
impl <'a, R: Reader<Offset=usize> + ?Sized> Header<'a, R> {
fn new(r: &'a R) -> Self {
Header(r, 0)
}
}
fn test<R: Reader + ?Sized>(_: Header<R>, _: Header<R>) {}
fn main() {
let buf1 = [0u8];
let slice1 = &buf1[..];
let header1 = Header::new(slice1);
let buf2 = [0u8];
let slice2 = &buf2[..];
let header2 = Header::new(slice2);
test(header1, header2);
}
Run Code Online (Sandbox Code Playgroud)