问题描述
以下代码示例是我遇到的问题的简化版本.
The following code sample is a minified version of a problem I have.
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
关联类型的代码.我试图概括我的代码,以便它可以与其他类型的偏移量一起使用.但是,添加此关联类型导致许多现有代码停止编译,并出现如下错误:
I currently have the code working using usize
instead of the Offset
associated type. I'm trying to generalize my code so it can work with other types for offset. However, adding this associated type has caused lots of existing code to stop compiling with errors like this:
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
的顺序可以解决此示例的问题,但我不想在所有地方(并且可能无法)进行此更改,并且我也不明白为什么这是一个问题.
Reversing the order of header1
and buf2
fixes the problem for this example, but I don't want to have to make this change everywhere (and may not be able to), and I don't understand why it is a problem.
推荐答案
原因
差异是问题的原因.
- 在
struct Header<R: Reader>(R, usize);
中,Header<R>
是协变.R
. - 但是,在
struct Header<R: Reader>(R, R::Offset);
中,Header<R>
是不变的.R
.
- In
struct Header<R: Reader>(R, usize);
,Header<R>
is covariant w.r.t.R
. - However, in
struct Header<R: Reader>(R, R::Offset);
,Header<R>
is invariant w.r.t.R
.
子类型是生命周期的安全转换.例如,可以将&'static [u8]
转换为&'a [u8]
.
Subtyping is a safe conversion of lifetimes. For example, &'static [u8]
can be converted to &'a [u8]
.
差异描述了如何将子类型提升为复杂类型.例如,如果Header<_>
是协变的,并且R
是S
的子类型,则Header<R>
是Header<S>
的子类型.不变结构不是这种情况.
Variance describes how subtyping is lifted to complex types. For example, if Header<_>
is covariant and R
is a subtype of S
, Header<R>
is a subtype of Header<S>
. This is not the case with invariant structs.
在当前的Rust中,特征始终是不变的,因为无法推断或无法在当前语法中指定特征方差.相同的限制适用于诸如R::Offset
的投影类型.
In current Rust, traits are always invariant, because trait variance can't be inferred nor specified in the current syntax. Same restrictions apply to projected types like R::Offset
.
在您的代码中,由于Header
是不变的,因此即使'a: 'b
,也无法将Header<&'a [u8]>
上载到Header<&'b [u8]>
.由于fn test
要求两个参数都具有相同的类型,因此编译器要求slice1
和slice2
具有相同的生存期.
In your code, since Header
is invariant, Header<&'a [u8]>
can't be upcasted to Header<&'b [u8]>
even if 'a: 'b
. Since fn test
requires the same type for both arguments, the compiler required the same lifetime for slice1
and slice2
.
如果可行的话,一种可能的即席解决方案是对fn test
的签名进行概括.
One possible ad-hoc solution is to generalize the signature for fn test
, if it is feasible.
fn test<R: Reader, S: Reader>(_: Header<R>, _: Header<S>) {}
另一种解决方案是使Header
协变.
Another solution is to make Header
covariant somehow.
如果type Offset
具有'static
边界,也许可以安全地假设Header
为协变,但是当前的编译器没有这么聪明的推论.
Maybe it is safe to assume Header
to be covariant if type Offset
has 'static
bound, but the current compiler doesn't do such a clever inference.
也许您可以将生存期拆分为Header
的参数.这样可以恢复协方差.
Perhaps you can split out lifetimes as a parameter for Header
. This recovers covariance.
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);
}
这篇关于由于关联的类型而导致错误的推断寿命的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!