【发布时间】:2019-01-02 16:26:05
【问题描述】:
感谢@francis-gagné 的excellent answer 另一个问题,我对方差的工作原理有了更清晰的认识。例如,包含引用的类型在其生命周期参数中是协变的,如下所示。
struct Foo<'a> (PhantomData<&'a str>);
/// Foo is covariant over its lifetime parameter
pub fn test_foo<'a:'b, 'b:'c, 'c>() {
let fa: Foo<'a> = Foo(PhantomData);
let fb: Foo<'b> = Foo(PhantomData);
let fc: Foo<'c> = Foo(PhantomData);
let v: Vec<Foo<'b>> = vec![fa, fb]; // fc is not accepted
}
另一方面,接受引用(或包含它的类型)的函数在其生命周期参数内是逆变的。
struct Bar<'a> (PhantomData<fn(&'a str)>);
/// Bar is contravariant over its lifetime parameter
pub fn test_bar<'a:'b, 'b:'c, 'c>() {
let ba: Bar<'a> = Bar(PhantomData);
let bb: Bar<'b> = Bar(PhantomData);
let bc: Bar<'c> = Bar(PhantomData);
let v: Vec<Bar<'b>> = vec![bb, bc]; // ba is not accepted
}
最后,带有生命周期参数的 trait 在其生命周期参数中是不变的。
pub trait Baz<'a> {}
impl<'a> Baz<'a> for () {}
/// Baz is invariant over its lifetime parameter
pub fn test_baz<'a:'b, 'b:'c, 'c>() {
let za: Box<dyn Baz<'a>> = Box::new(());
let zb: Box<dyn Baz<'b>> = Box::new(());
let zc: Box<dyn Baz<'c>> = Box::new(());
let v: Vec<Box<dyn Baz<'b>>> = vec![zb]; // za and zx are not accepted
}
这是有道理的,因为特征可以通过协变和逆变类型来实现,如下所示。
impl<'a> Baz<'a> for Foo<'a> {}
impl<'a> Baz<'a> for Bar<'a> {}
我的问题是:我可以强制特征在其生命周期参数中是协变的吗?我希望有一个标记特征,例如:
trait Baz<'a>: Covariant<'a> {}
这将使使用逆变类型实现该特征是非法的,并允许za 成为上述test_baz 函数中向量v 的成员。
当然,能够做相反的事情(强制特征是逆变的)也可能很有用......
【问题讨论】:
-
这是post summarizing all variance rules in Rust。有人可能会觉得它很有用。
标签: rust traits covariance