使用 by 委托给另一个相同类型的对象甚至无法编译

Delegation to another object of same type using by does not even compile

我正在尝试了解委托关键字 by 的工作原理。
因此,委托实现一个接口是很清楚的,例如

class Manager(clientele: List<Client> = ArrayList()): List<Client> by clientale

但以下不起作用:

data class Client(val name: String, val postalCode: Int)  
fun createClient() = Client("Bob", 1234)
val bigClient: Client by createClient() // compilation error

我收到错误:

Missing getValue(Nothing?, KProperty<*>) method delegate of type Client

我认为如果两个对象是相同的,那么从一个对象到另一个对象(一个客户端一个客户端)的委托会起作用。
有人可以解释这里的错误是什么以及我做错了什么吗?

不幸的是,这并不是属性委托的确切工作方式。基于 documentation:

For a read-only property (i.e. a val), a delegate has to provide a function named getValue that takes the following parameters:

  • thisRef - must be the same or a supertype of the property owner;
  • property - must be of type KProperty<*> or its supertype.

For a mutable property (a var), a delegate has to additionally provide a function named setValue that takes the following parameters:

  • thisRef - same as for getValue();
  • property - same as for getValue();
  • newValue - must be of the same type as the property or its subtype.

[...] Both of the functions need to be marked with the operator keyword.

因此,为了使您的示例正常工作,您必须添加满足上述要求的 getValue() 方法:

data class Client(val name: String, val postalCode: Int) {
    operator fun getValue(thisRef: Nothing?, property: KProperty<*>): Client = this
}

您还可以使用和实现提供所需方法的 ReadOnlyPropertyReadWriteProperty 接口:

data class Client(val name: String, val postalCode: Int) : ReadOnlyProperty<Nothing?, Client> {
    override fun getValue(thisRef: Nothing?, property: KProperty<*>): Client = this
}

编辑:

What is this getValue() supposed to do?

让我用一个更抽象的例子进一步解释一下。我们有以下 classes:

class MyDelegate : ReadWriteProperty<MyClass, String> {

    private var delegateProperty: String = ""

    override fun getValue(thisRef: MyClass, property: KProperty<*>): String {
        println("$thisRef delegated getting the ${property.name}'s value to $this")
        return delegateProperty
    }

    override fun setValue(thisRef: MyClass, property: KProperty<*>, value: String) {
        println("$thisRef delegated setting the ${property.name}'s value to $this, new value: $value")
        delegateProperty = value
    }
}

class MyClass {
    var property: String by MyDelegate()
}

以上 MyClass 或多或少会被编译为:

class MyClass {
    private var property$delegate: MyDelegate = MyDelegate()

    var property: String
        get() = property$delegate.getValue(this, this::property)
        set(value) = property$delegate.setValue(this, this::property, value)
}

因此您可以看到编译器要求委托具有 getValue()setValue() 方法用于可变属性 (var) 或只有 getValue() 用于不可变属性 ( val), 因为它使用它们分别获取和设置委托的 属性 的值。


What are Nothing and KProperty<*>?

KProperty<*> 是一个 Kotlin class,代表一个 属性 并提供它的元数据。

Nothing 是一种表示不存在的值的类型。从授权的角度来看,这完全无关紧要。它出现在这种情况下,因为你可能在任何 class 之外定义了 bigClient 属性 所以它没有所有者,因此 thisRefNothing.