以下代码示例是我遇到的问题的缩小版本。
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);
}
我目前使用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
撤消header1
和buf2
的顺序修复了此示例的问题,但我不想在任何地方(也可能无法)进行此更改,并且我不明白为什么这是一个问题。
答案 0 :(得分:5)
Variance是导致问题的原因。
struct Header<R: Reader>(R, usize);
中,Header<R>
协变 w.r.t. R
。struct Header<R: Reader>(R, R::Offset);
中,Header<R>
不变 w.r.t. R
。 子类型是对生命周期的安全转换。例如,&'static [u8]
可以转换为&'a [u8]
。
Variance 描述了如何将子类型提升到复杂类型。例如,如果Header<_>
是协变的且R
是S
的子类型,则Header<R>
是Header<S>
的子类型。对于不变结构,情况并非如此。
在当前的Rust中,特征始终是不变的,因为在当前语法中无法推断或指定特征差异。同样的限制适用于R::Offset
等预计类型。
在您的代码中,由于Header
不变,Header<&'a [u8]>
即使Header<&'b [u8]>
也无法升级到'a: 'b
。由于fn test
要求两个参数使用相同的类型,因此编译器需要slice1
和slice2
的相同生命周期。
一种可能的临时解决方案是概括fn test
的签名,如果可行的话。
fn test<R: Reader, S: Reader>(_: Header<R>, _: Header<S>) {}
另一个解决方案是以某种方式使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);
}