Kotlin star projection on contravariant types

2019-09-22 05:27发布

问题:

I am reading and trying to understand Kotlin type projections, sometimes I come up with confusing things like this:

What does it mean to contravariant type to have a star projection and how does it come up to

回答1:

This is also explained in the Kotlin documentation:

For Foo<in T>, where T is a contravariant type parameter, Foo<*> is equivalent to Foo<in Nothing>. It means there is nothing you can write to Foo<*> in a safe way when T is unknown.

Example

We have a class Foo<T> with contravariant T (declaration-site), i.e. Foo only works as a consumer of T:

class Foo<in T> {
    fun accept(t: T) {
        println(t)
    }
}

We can use this type in simple generic functions as follows:

fun <F> usingFoo(con: Foo<F>, t: F) {
    con.accept(t)
}

(used F in order to distinguish from class type parameter T)

This works fine since we use Foo as intended: As a consumer of Ts.

Now, your quote simply says that having a parameter of type con: Foo<*> instead of con: Foo<T> would have the following effect: "you can't call any methods that have T in the signature".

Thus, the following fails:

fun <F> usingFoo(con: Foo<*>, t: F) {
    con.accept(t) //not allowed!!
}

It's not safe to call accept with an instance of F because we don't know the type of Foo (denoted by star projection).

Star Projection: Sometimes you want to say that you know nothing about the type argument, but still want to use it in a safe way. The safe way here is to define such a projection of the generic type, that every concrete instantiation of that generic type would be a subtype of that projection.