What is an example of contravariant use in Rust?

2020-05-01 06:02发布

问题:

In the Nomicon's section about subtyping, it says contravariance is available for a function pointer type. However, I can't find any good examples of this. I tried to code a struct with a function pointer, but the contravariance doesn't seem to work.

What is a code example of this?

回答1:

Rust's notion of subtyping only applies to lifetimes.


Searching for the term "contra" on the page you linked has numerous relevant paragraphs:

Actually witnessing contravariance is quite difficult in Rust, though it does in fact exist.

NOTE: the only source of contravariance in the language is the arguments to a function, which is why it really doesn't come up much in practice. Invoking contravariance involves higher-order programming with function pointers that take references with specific lifetimes (as opposed to the usual "any lifetime", which gets into higher rank lifetimes, which work independently of subtyping).

And that's why function types, unlike anything else in the language, are contravariant over their arguments.

The page ends with an example of all the types of contravariance. Applying it...

Contravariance

struct MyContraType<Mixed> {
    k1: fn(Mixed), // contravariant over Mixed
}

fn contra_example<'short>(
    mut a: MyContraType<&'short u8>,
    mut b: MyContraType<&'static u8>,
    x: fn(&'short u8),
    y: fn(&'static u8),
) {
    a.k1 = x;
    a.k1 = y; // Fails
    b.k1 = x;
    b.k1 = y;
}

The contravariant example does not allow substituting 'static for 'short:

error[E0308]: mismatched types
  --> src/lib.rs:12:12
   |
12 |     a.k1 = y;
   |            ^ lifetime mismatch
   |
   = note: expected type `fn(&'short u8)`
              found type `fn(&'static u8)`
note: the lifetime 'short as defined on the function body at 5:19...
  --> src/lib.rs:5:19
   |
5  | fn contra_example<'short>(
   |                   ^^^^^^
   = note: ...does not necessarily outlive the static lifetime

Covariance

struct MyCoType<Mixed> {
    k1: fn() -> Mixed, // covariant over Mixed
}

fn co_example<'short>(
    mut a: MyCoType<&'short u8>,
    mut b: MyCoType<&'static u8>,
    x: fn() -> &'short u8,
    y: fn() -> &'static u8,
) {
    a.k1 = x;
    a.k1 = y;
    b.k1 = x; // Fails
    b.k1 = y;
}

The covariant example does not allow substituting 'short for 'static:

error[E0308]: mismatched types
  --> src/lib.rs:29:12
   |
29 |     b.k1 = x;
   |            ^ lifetime mismatch
   |
   = note: expected type `fn() -> &'static u8`
              found type `fn() -> &'short u8`
note: the lifetime 'short as defined on the function body at 21:15...
  --> src/lib.rs:21:15
   |
21 | fn co_example<'short>(
   |               ^^^^^^
   = note: ...does not necessarily outlive the static lifetime