使用 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
}
您还可以使用和实现提供所需方法的 ReadOnlyProperty
和 ReadWriteProperty
接口:
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
属性 所以它没有所有者,因此 thisRef
是 Nothing
.
我正在尝试了解委托关键字 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 namedgetValue
that takes the following parameters:
thisRef
- must be the same or a supertype of the property owner;property
- must be of typeKProperty<*>
or its supertype.For a mutable property (a
var
), a delegate has to additionally provide a function namedsetValue
that takes the following parameters:
thisRef
- same as forgetValue()
;property
- same as forgetValue()
;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
}
您还可以使用和实现提供所需方法的 ReadOnlyProperty
和 ReadWriteProperty
接口:
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
属性 所以它没有所有者,因此 thisRef
是 Nothing
.