gpt4 book ai didi

generics - Kotlin 中 ReadOnly 和 ReadWrite 委托(delegate)属性的通用方差

转载 作者:行者123 更新时间:2023-12-02 13:43:48 26 4
gpt4 key购买 nike

我理解协变和逆变。我也读过 Eric Lippert 的优秀文章 here .

但是,我无法理解标准库中以下接口(interface)的方差的实际应用,这些接口(interface)是编写自定义委托(delegate)属性所需的。

interface ReadOnlyProperty<in R, out T> {
operator fun getValue(thisRef: R, property: KProperty<*>): T
}

interface ReadWriteProperty<in R, T> {
operator fun getValue(thisRef: R, property: KProperty<*>): T
operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
}

由于属性委托(delegate)是由编译器翻译的,因此很难找到一个实际的例子来说明方差发挥作用。很难绕开我的头,我相信这是有原因的。

有人可以帮忙解释一下吗?

最佳答案

委托(delegate)属性接口(interface)对于说明差异不是很有用,因为它们是可选的,而且您实际上从不直接调用这些函数。而且您不太可能使用它们构建类层次结构或将它们的实例分配给变量。

在这种情况下,方差没有用,而只是表明兼容性。

对于代表,thisRef具有逆变类型,表示在某个类中工作的只读委托(delegate)也允许在该类的子类中使用。

假设你有一个 Cat 类会喵喵叫,还有一个委托(delegate)实现会在你读取委托(delegate)属性时让它喵喵叫:

open class Cat {
fun meow() {
println("meow")
}
}

class MeowingDelegate<T>(private val value: T): ReadOnlyProperty<Cat, T> {
override fun getValue(thisRef: Cat, property: KProperty<*>): T {
thisRef.meow()
return value
}
}

您可以在 Cat 的子类中使用此委托(delegate)。因为子类会有父类(super class)的方法,所以子类也能喵喵叫。签名表明 MeowingDelegate 及其 in Cat type 有资格作为具有更具体类型的委托(delegate)的子类,因此可以在 Cat 子类中使用。
open class Kitten: Cat() {
val x: Int by MeowingDelegate(1)
}

编辑:
对于协变 T对于 ReadOnlyProperty,这意味着提供一种对象类型的委托(delegate)也可以用作该对象的父类(super class)型的提供者。因此,如果我有一个提供 Kittens 的委托(delegate),它也可以用于提供 Cats:
open class Cat
open class Kitten: Cat()

class KittenDelegate: ReadOnlyProperty<Any?, Kitten> {
override fun getValue(thisRef: Any?, property: KProperty<*>): Kitten {
return Kitten()
}
}

class Sample {
val cat: Cat by KittenDelegate()
}

由于类型 T对于 ReadWriteProperty 是不变的,您不能使用只能返回 Kittens 的委托(delegate)来执行此操作。这是有道理的,因为委托(delegate)还必须允许您设置属性,因此它不能接受任何 Cat 并将其视为小猫。

同样,这些委托(delegate)接口(interface)并不是理解差异的好例子,因为它们通常不用作接口(interface)。对于更实际的示例,您可以查看熟悉的集合类。

只读 List具有协变类型。这使您可以轻松地将集合转换为更具体的类型:
class Kennel (val cats: List<Cats>)

val kittens: List<Kitten> = listOf(Kitten(), Kitten())
val kennel = Kennel(kittens) // OK

你不能用 MutableList 做到这一点,因为类型是不变的。
class Kennel (val cats: MutableList<Cats>)

val kittens: MutableList<Kitten> = mutableListOf(Kitten(), Kitten())
val kennel = Kennel(kittens) // Compiler error

但是 MutableList 必须使用不变类型来定义。一个 MutableList<Kitten>不能接受任何类型的 Cat 添加到它,所以将它转换为 MutableList<Cat> 是没有意义的.相反,一个 MutableList<Cat>不一定只有 Kittens 在其中,因此能够将其转换为 MutableList<Kitten> 是没有意义的.当然,在使用现场,你可以根据你的需要给它变化,这就是为什么一个 MutableList<Kitten>可以转换为 MutableList<out Cat> .

对于类级逆变,我想不出一个在声明中包含它的通用 stdlib 类。所以假设我们创造了一个宠物猫。然后我们有一些想要抚摸的小猫。一个 CatPetter足以用作 Petter<Kitten>因为小猫有资格成为猫,因此可以被 CatPetter 宠爱。 .如果 Petter 的类型是不变的,这是不允许的。
open class Cat {
fun purr() {
println("rrrr")
}
}
open class Kitten: Cat()

interface Petter<in T: Cat> {
fun pet(recipient: T)
}

class CatPetter: Petter<Cat> {
override fun pet(recipient: Cat) {
recipient.purr()
}
}

class BoxOfKittens (val petter: Petter<Kitten>)

val x = BoxOfKittens(CatPetter()) // OK

关于generics - Kotlin 中 ReadOnly 和 ReadWrite 委托(delegate)属性的通用方差,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60978132/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com