假设您有这个泛型类 Crate,您打算用它来存储水果。这个类在 T中是不变的。这意味着,这个类可以消费和生产 T(水果)。换句话说,这个类具有以 T作为参数(使用)以及返回 T(生成)的函数。size()函数是独立于 T 的,它既不接受 T也不返回 T:
class Crate<T> {
private val items = mutableListOf<T>()
fun produce(): T = items.last()
fun consume(item: T) = items.add(item)
fun size(): Int = items.size
}
但是,如果您只是想使用这个已经存在的类作为生产者(out T)或者仅仅作为消费者(in T) ,或者不想使用 T,而仅仅使用它的与 T 无关的函数(如 size()) ,该怎么办呢?不用担心意外使用不需要的功能?
fun useAsProducer(producer: Crate<out Fruit>) {
// T is known to be out Fruit, so produces Fruit and its subtypes.
val fruit = producer.produce() // OK
// Fruit is guaranteed. Can use functions and properties of Fruit.
fruit.getColor() // OK
// Consumer not allowed because you don't want to accidentally add
// oranges, if this is a Crate<Apple>
producer.consume(Orange()) // Error
}
fun useAsConsumer(consumer: Crate<in Orange>) {
// Produces Any?, no guarantee of Orange because this could
// be a Crate<Fruit> with apples in it.
val anyNullable = consumer.produce() // Not useful
// Not safe to call functions of Orange on the produced items.
anyNullable.getVitaminC() // Error
// T is known to be in Orange, so consumes Orange and its subtypes.
consumer.consume(MandarinOrange()) // OK
}
恒星投影不是 T的生产者,也不是消费者
通过将 Crate投影为 *,你告诉编译器: “当我不小心使用 Crate类作为 T的生产者或使用者时,给我一个错误,因为我不想使用使用和生产 T的函数或属性。我只想安全地使用与 T 无关的函数和属性,比如 size()”:
fun useAsStar(star: Crate<*>) {
// T is unknown, so the star produces the default supertype Any?.
val anyNullable = star.produce() // Not useful
// T is unknown, cannot access its properties and functions.
anyNullable.getColor() // Error
// Cannot consume because you don't know the type of Crate.
star.consume(Fruit()) // Error
// Only use the T-independent functions and properties.
star.size() // OK
}
fun useAsAny(any: Crate<Any>) {
// T is known to be Any. So, an invariant produces Any.
val anyNonNull = any.produce() // OK
// T is known to be Any. So, an invariant consumes Any.
any.consume(Fruit()) // OK
// Can use the T-independent functions and properties, of course.
any.size() // OK
}
class ProducerCrate<out T : Fruit> {
private val fruits = listOf<T>()
fun produce() : T = fruits.last()
}
使用地点
fun useProducer(star: ProducerCrate<*>) {
// Even though we project * here, it is known to be at least a Fruit
// because it's an upper bound at the declaration-site.
val fruit = star.produce() // OK
// Fruit is guaranteed. Can use functions and properties of Fruit.
fruit.getColor() // OK
}
申报现场用户的星形投影
声明-地点
class ConsumerCrate<in T> {
private val items = mutableListOf<T>()
fun consume(item: T) = items.add(item)
fun size(): Int = items.size
}
使用地点
fun useConsumer(consumer: ConsumerCrate<*>) {
// Cannot consume anything, because the lower bound is not supported
// in Kotlin and T is unknown
consumer.consume(Orange()) // Error
// Only useful for T-independent functions and properties.
consumer.size() // OK
}
请注意,Kotlin 不支持下限。因此,在上面的 ConsumerCrate类中,我们不能有类似于 in T super Orange(下界)的东西,就像我们有 out T : Orange(上界)一样。
声明位置不变量的星投影
声明-地点
class ProducerConsumerCrate<T : Fruit> {
private val fruits = mutableListOf<T>()
fun produce(): T = fruits.last()
fun consume(fruit: T) = fruits.add(fruit)
}
使用地点
fun useProducerConsumer(producerConsumer: ProducerConsumerCrate<*>) {
// Even though we project * here, T is known to be at least a Fruit
// because it's the upper bound at the declaration-site.
val fruit = producerConsumer.produce() // OK
// Fruit is guaranteed. Can use functions and properties of Fruit.
fruit.getColor() // OK
// Consumer not allowed because you don't want to accidentally add
// oranges, if this crate is a Crate<Apple>.
producerConsumer.consume(Fruit()) // Error
}