可以将属性的get set委托给其他类
class Example {
var p: String by Delegate()
}
当读取或者写入p时,Delegate
的getValue
和setValue
会被调用
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, thank you for delegating '${property.name}' to me!"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$value has been assigned to '${property.name} in $thisRef.'")
}
}
委托属性的要求
对于val
变量,委托需要提供方法getValue
,接收两个参数
- receiver: property属主类型或者其父类。
- metadata:KProperty或者其父类
- return type必须是属性类型或其子类
对var
变量,委托需要提供setValue
方法,
- receiver:同上
- metadata:同上
- new value: property类型或者父类
getValue
和setValue
都需要用operator
修饰
Lazy delegate
lazy属性接收一个lambda表达式,在第一次get的时候执行lambda表达式,存储并返回lambda表示的结果
val lazyValue: String by lazy {
println("computed!")
"Hello"
}
lazy表达式的执行是同步的,如果想取消同步,在lazy的构造函数里传入LazyThreadSafetyMode.PUBLICATION
Observable delegate
Delegates.observable()接收两个参数,第一个是初始化的值,第二个是变量修改后调用的lambda函数,lambda函数接收三个参数,property, old value, new value。
import kotlin.properties.Delegates
class User {
var name: String by Delegates.observable("<no name>") {
prop, old, new ->
println("$old -> $new")
}
}
fun main(args: Array<String>) {
val user = User()
user.name = "first"
user.name = "second"
}
如果想拦截变量的修改,使用Delegates.vetoable()
。vetoable接收两个参数,第一个是初始值,第二个是变量改变前调用的lambda函数,如果lambda返回false,则变量不会被修改
将变量存储在map中
class User(val map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}
val user = User(mapOf(
"name" to "John Doe",
"age" to 25
))
println(user.name) // Prints "John Doe"
println(user.age) // Prints 25
如果是可变property可以使用MutableMap
class MutableUser(val map: MutableMap<String, Any?>) {
var name: String by map
var age: Int by map
}
网友评论