我可以强制性状是协变的吗? [英] Can I force a trait to be covariant?

查看:66
本文介绍了我可以强制性状是协变的吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

感谢@francis-gagné的

Thanks to @francis-gagné 's excellent answer to another question, I have a clearer view of how variance works. For example, a type containing a reference is covariant over its lifetime parameter, as demonstrated below.

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
}

另一方面,接受引用(或包含引用的类型)的函数与其生命周期参数相反.

On the other hand a function accepting a reference (or a type containing it) is contravariant over its lifetime parameter.

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 在其生存期参数上是不变的.

Finally, a trait with a lifetime parameter is invariant over its lifetime parameter.

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
}

这是有道理的,因为特征既可以通过协变类型也可以通过反变量类型实现,如下所示.

That makes sense, because the trait could be implemented both by a covariant and a contravariant type, as illustrated below.

impl<'a> Baz<'a> for Foo<'a> {}
impl<'a> Baz<'a> for Bar<'a> {}

我的问题是:我可以强制某个特征在其生存期参数上进行协变吗?我希望有一个标记特征,例如:

My question is: can I force a trait to be covariant over its lifetime parameter? I would expect a marker trait such as:

trait Baz<'a>: Covariant<'a> {}

这将使使用逆变类型实现该特征成为非法,并允许 za 成为 test_baz 中向量 v 的成员code>以上功能.

that would make it illegal to implement that trait with a contravariant type, and allow za to be a member of the vector v in the test_baz function above.

当然,能够做相反的事情(迫使一个性状成为逆变)也可能是有用的...

Of course, being able to do the opposite (force a trait to be contravariant) could be useful as well...

操场上的例子

推荐答案

否.

您可以表达为 any 'x 实现Baz<'x> 的值":

You can express "a value that implements Baz<'x> for any 'x":

pub fn test_baz<'a:'b, 'b:'c, 'c>() {
    let za: Box<dyn for<'x> Baz<'x>> = Box::new(());
    let zb: Box<dyn for<'x> Baz<'x>> = Box::new(());
    let zc: Box<dyn for<'x> Baz<'x>> = Box::new(());

    let v: Vec<Box<dyn for<'x> Baz<'x>>> = vec![za, zb, zc];
}

但是(从Rust 1.31开始)您不能为'b>编写 Box< dyn.Baz''x>> ,即使您可以,该语法也只能使用一生.它不会让您表达类型参数的协方差.

But you can't (as of Rust 1.31) write Box<dyn for<'x: 'b> Baz<'x>>, and even if you could, that syntax would only work for lifetimes; it wouldn't let you express covariance over type parameters.

这篇关于我可以强制性状是协变的吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆