一般来说,方差决定了参数化类型之间关于其参数的子类型关系:
Covariance: T <: U => F[T] <: F[U]
Contravariance: T <: U => F[U] <: F[T]
Invariance: T <: U => neither of the above
Bivariance: T <: U => both of the above
你的类型是自然逆变的:它的方法只使用类型为T的值,但不产生它们;这就是所谓的消费者类型。然而,Rust 中的子类型非常有限。据我所知,唯一允许任何类型的子类型关系的类型是引用(例如,您可以将&'static str 传递给&'a str 变量,因为'static 生命周期大于或等于任何其他生命周期,所以@ 987654326@ 是任何'a 的&'a str 的子类型。
所以,如果我理解正确,您确实需要方差注释。如果您的T 参数可以作为参考,请使用ContravariantType,这样您就可以这样做:
fn push_something_to(os: OutputStream<&'static str>) { ... }
let s: OutputStream<&'a str> = ...; // and 'a is less than 'static
push_something_to(s); // this is safe to do because &'static str is valid &'a str
但不能这样做:
let s: OutputStream<int> = ...;
push_something_to(s); // oops, push_something_to expects stream of &'static str
InvariantType 两者都被禁止。
但是,我这边似乎有一些深刻的误解,因为文档中关于方差标记的代码和我自己的代码都不适用于我当前的 Rust:
use std::ptr;
use std::mem;
struct S<T> { x: *const () }
fn get<T>(s: &S<T>, v: T) {
unsafe {
let x: fn(T) = mem::transmute(s.x);
x(v)
}
}
fn main() {
let s: S<int> = S { x: ptr::null() };
get::<Box<int>>(&s, box 1);
}
根据文档,由于默认情况下参数化类型是双变量的,这应该可以编译,但事实并非如此:它就像参数是不变的一样。
这是我自己的例子:
#![allow(dead_code)]
type F<T> = fn(T);
fn test_1<'a>(f: F<&'a str>) -> F<&'static str> {
f
}
struct S<T> {
_m: std::kinds::marker::ContravariantType<T>
}
fn test_2<'a>(s: S<&'a str>) -> S<&'static str> {
s
}
fn main() {}
据我了解,这个程序应该可以编译,但它没有:
<anon>:9:5: 9:6 error: mismatched types: expected `S<&'static str>` but found `S<&'a str>` (lifetime mismatch)
<anon>:9 s
^
<anon>:8:47: 10:2 note: the lifetime 'a as defined on the block at 8:46...
<anon>:8 fn test<'a>(s: S<&'a str>) -> S<&'static str> {
<anon>:9 s
<anon>:10 }
note: ...does not necessarily outlive the static lifetime
如果我删除 S 和 test_2,它编译得很好,这表明函数类型在其参数类型方面确实是逆变的。
我不知道发生了什么事,看起来值得另一个问题。