[英]How to implement property delegate that works with an arbitrary type
我正在嘗試實現自定義屬性委托以將道具存儲在 Map 中(就像在docs中一樣,出於教育目的)
委托實施必須:
我寫了一個滿足第一個條件的代碼:
import kotlin.reflect.KProperty
fun main() {
val e = Example(PropInMapDelegate())
e.myProp = 1;
println(e.myProp) // e.myProp is "Any?" :(
}
class Example(propInMapDelegate: PropInMapDelegate) {
var myProp by propInMapDelegate
}
class PropInMapDelegate {
private val _map: HashMap<String, Any?> = HashMap()
operator fun getValue(thisRef: Any, property: KProperty<*>): Any? {
return _map[property.name]
}
operator fun setValue(thisRef: Any, property: KProperty<*>, value: Any?) {
_map[property.name] = value
}
}
但是,它有兩個明顯的問題:
var myProp: Int by propInMapDelegate
會導致錯誤:錯誤 #1
Property delegate must have a 'getValue(Example, KProperty*>)' method. None of the following functions are suitable.
getValue(Any?, KProperty<*>) defined in PropInMapDelegate
錯誤#2
Property delegate must have a 'setValue(Example, KProperty*>, Int)' method. None of the following functions are suitable.
setValue(Any?, KProperty<*>, Any?) defined in PropInMapDelegate
我嘗試使用 generics 來進行類型推斷,但失敗了。
像這樣更改PropInMapDelegate
實現:
class PropInMapDelegate {
private val _map: HashMap<String, Any?> = HashMap()
operator fun <T>getValue(thisRef: Any, property: KProperty<*>): T? {
return _map[property.name] as T // That feels very wrong
}
operator fun <T>setValue(thisRef: Any, property: KProperty<*>, value: T?) {
_map[property.name] = value
}
}
並使用以下
class Example(propInMapDelegate: PropInMapDelegate) {
var myProp: Int by propInMapDelegate // error (see below)
}
導致:錯誤#1
Property delegate must have a 'getValue(Example, KProperty*>)' method. None of the following functions are suitable.
getValue(Any, KProperty<*>) where T = Int for operator fun <T> getValue(thisRef: Any, property: KProperty<*>): T? defined in PropInMapDelegate
錯誤#2
Property delegate must have a 'setValue(Example, KProperty*>, Int)' method. None of the following functions are suitable.
setValue(Any, KProperty<*>, Int?) where T = Int for operator fun <T> setValue(thisRef: Any, property: KProperty<*>, value: T?): Unit defined in PropInMapDelegate
問題:
as
它,所以它可能沒問題?public inline operator fun <V, V1 : V> MutableMap<in String, out @Exact V>.getValue(thisRef: Any?, property: KProperty<*>): V1 =
@Suppress("UNCHECKED_CAST") (getOrImplicitDefault(property.name) as V1)
我認為錯誤消息的措辭方式誤導了您。 “示例”不是不匹配的部分。 由於Example
是Any
的子類型,因此您的getValue()
function 簽名的那部分很好。
不匹配的部分是您要返回T?
但您正試圖將它用於不可為 null 的屬性。
如果您將屬性更改為可為空,它將起作用:
var myProp: Int? by propInMapDelegate
或者,如果您將運算符 function 更改為返回不可為 null 的值,它將起作用:
operator fun <T> getValue(thisRef: Any, property: KProperty<*>): T {
return _map[property.name] as T
}
請注意,如果 map 中不存在該鍵的值並且您將其用於不可為 null 的屬性,則轉換as T
將失敗,因為null
無法轉換為不可為 null 的 T。
關於標記為 3 的問題:如您在標准庫源代碼中所見,如果您使用任意值類型的 map,則強制轉換是不可避免的。 這是為此目的使用 map 的潛在危險的一部分。 也有可能 map 根本沒有與請求的屬性名稱匹配的值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.