var someModel: someViewModel by notNullAndObservable { vm ->
...
}
我不明白
by
关键字的意义是什么。简单来说,你可以理解关键字by
为由提供。
从属性使用者的角度来看,val
表示具有getter(get)的内容,var
表示具有getter和setter(get、set)的内容。对于每个var
属性,都有默认的getter和setter方法提供程序,我们不需要显式指定。
但是,当使用by
关键字时,您在说明此getter/getter&setter已在其他地方提供(即已被委派)。它是由by
后面的函数提供的。
因此,您代理了某些明确的功能来完成这个内置的获取和设置方法的工作。
一个非常常见的示例是用于延迟加载属性的by lazy
。此外,如果您正在使用像Koin这样的依赖注入库,您会看到许多像这样定义的属性:
var myRepository: MyRepository by inject() //inject is a function from Koin
在类的定义中,它遵循同样的原则,它定义了一些函数所提供的位置,但它可以引用任何一组方法/属性,而不仅仅是get和set。class MyClass: SomeInterface by SomeImplementation, SomeOtherInterface
这段代码的意思是: “我是MyClass类,提供了SomeInterface接口的函数,它们由SomeImplementation提供。我会自己实现SomeOtherInterface接口(那是隐式的,所以没有by关键字)。”
MyClass
的最后一个例子可以理解,但像 var myRepository: MyRepository by inject()
这样的语句对于像我这样的初学者来说毫无意义。 - Bhavesh Achhadaby
的两种用途,第一种是委托属性,这是您上面所使用的用法:
有某些常见类型的属性,尽管我们每次需要它们时都可以手动实现它们,但一劳永逸地实现它们并放入库中会非常好。例如延迟初始化属性:
只有在首次访问时才计算值
可观察属性:
监听器会收到此属性更改的通知
将属性存储在映射中,而不是在单独的字段中等等。
在这里,您将getter / setter委托给另一个执行工作的类,并且可以包含通用代码。例如,Kotlin的某些依赖注入器支持通过委托getter从由依赖注入引擎管理的实例注册表中接收值来实现此模型。
接口/类委托是其他用途:
委托模式已被证明是实现继承的一个好替代方案,而Kotlin在本地支持此模式,不需要零样板代码。类Derived可以从接口Base继承,并将其所有公共方法委托给指定对象。
在这里,您可以将接口委托给另一个实现,因此实现类只需要覆盖它想要更改的内容,而其余方法则委托回更完整的实现。
一个活生生的例子是Klutter Readonly/Immutable collections,在那里它们实际上只是将特定的集合接口委托给另一个类,然后在readonly实现中覆盖任何需要不同的内容。这样就不必手动委托所有其他方法,从而节省了很多工作。
这两者都包含在Kotlin语言参考文档中。从那里开始了解该语言的基础主题。
e.p = "NEW"
后,如果我们执行 println(e.p)
,它会打印出新值 NEW
吗?实际结果是它与原始值相同。为什么会这样? - LiuWenbin_NO.班级的委派:
interface BaseInterface {
val value: String
fun f()
}
class ClassA: BaseInterface {
override val value = "property from ClassA"
override fun f() { println("fun from ClassA") }
}
// ClassB implements BaseInterface using all public members of classA.
class ClassB: BaseInterface by ClassA()
object SampleBy {
@JvmStatic fun main(args: Array<String>) {
val classB = ClassB()
println(classB.value)
classB.f()
}
}
结果:
property from ClassA
fun from ClassA
财产委托:
import kotlin.reflect.KProperty
class Delegate {
// for get() method, ref - a reference to the object from
// which property is read. prop - property
operator fun getValue(ref: Any?, prop: KProperty<*>) = "textA"
// for set() method, 'v' stores the assigned value
operator fun setValue(ref: Any?, prop: KProperty<*>, v: String) {
println("value = $v")
}
}
object SampleBy {
var s: String by Delegate() // delegation for property
@JvmStatic fun main(args: Array<String>) {
println(s)
s = "textB"
}
}
结果:
textA
value = textB
参数委派:
// for val properties Map is used; for var MutableMap is used
class User(mapA: Map<String, Any?>, mapB: MutableMap<String, Any?>) {
val name: String by mapA
val age: Int by mapA
var address: String by mapB
var id: Long by mapB
}
object SampleBy {
@JvmStatic fun main(args: Array<String>) {
val user = User(mapOf("name" to "John", "age" to 30),
mutableMapOf("address" to "city, street", "id" to 5000L))
println("name: ${user.name}; age: ${user.age}; " +
"address: ${user.address}; id: ${user.id}")
}
}
结果:
name: John; age: 30; address: city, street; id: 5000