在为Android开发时,我有时会遇到这样的事情:
var someModel: someViewModel by notNullAndObservable { vm ->
...
}
我不明白by
关键字的重要性是什么。
答案 0 :(得分:45)
在Kotlin reference中,您会发现by
有两种用途,第一种是Delegated Properties,这是您在上面的用途:
有一些常见的属性,虽然我们可以在每次需要时手动实现它们,但是一劳永逸地实现它们并放入库中会非常好。示例包括延迟属性:仅在首次访问时计算值, 可观察属性:监听器收到有关此属性更改的通知, 将属性存储在地图中,而不是分别存储在单独的字段中。
在这里,您将getter / setter委托给另一个完成工作的类,并且可以包含公共代码。另一个例子是,Kotlin的一些依赖注入器通过将getter委托给从依赖注入引擎管理的实例注册表中接收一个值来支持这个模型。
Interface/Class delegation是另一种用法:
委托模式已被证明是实现继承的一个很好的替代方案,Kotlin支持它本身需要零样板代码。 Derived类可以从接口Base继承并将其所有公共方法委托给指定的对象
在这里,您可以将接口委托给另一个实现,因此实现类只需要覆盖它想要更改的内容,而其余的方法则委托回更全面的实现。
一个实例是Klutter Readonly/Immutable collections,他们实际上只是将特定的集合接口委托给另一个类,然后覆盖readonly实现中需要不同的任何东西。节省大量工作而不必手动委派所有其他方法。
Kotlin language reference 涵盖了这两个问题,从那里开始了解该语言的基本主题。
答案 1 :(得分:19)
语法为:
val/var <property name>: <Type> by <expression>.
by之后的表达式是委托人
如果我们尝试访问属性 p 的值,换句话说,如果我们调用属性 p 的 get()方法,调用 Delegate 实例的 getValue()方法。
如果我们尝试设置属性 p 的值,换句话说,如果我们调用属性 p 的 set()方法,调用 Delegate 实例的 setValue()方法。
答案 2 :(得分:14)
简单来说,您可以将 by 关键字理解为由提供。
从财产消费者的角度来看,val是具有getter(get)的东西,而var是具有getter和setter(get,set)的东西。对于每个 var 属性,都有一个默认的get和set方法提供程序,我们无需明确指定。
但是,当使用 by 关键字时,您表示此getter / getter&setter是在其他地方提供的(即已被委派),它是 by 之后的功能。
因此,不是使用此内置的get和set方法,而是将该工作委托给某些显式函数。
一个非常常见的示例是 by lazy 用于延迟加载属性。 另外,如果您正在使用像Koin这样的依赖注入库,则会看到许多这样定义的属性:
var myRepository: MyRepository by inject() //inject is a function from Koin
在类定义中,它遵循相同的原理,它定义了提供某些功能的位置,但它可以引用任何方法/属性集,而不仅是get和set。
class MyClass: SomeInterface by SomeImplementation, SomeOtherInterface
这段代码说: 我是MyClass类,并且提供SomeImplementation提供的接口SomeInterface接口的功能。 我将自己实现SomeOtherInterface(这是隐式的,因此没有实现)
答案 3 :(得分:7)
财产委派:
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
班级委派:
interface BaseInterface {
val value: String
fun f()
}
class ClassA: BaseInterface {
override val value = "property from ClassA"
override fun f() { println("fun from ClassA") }
}
// The ClassB can implement the BaseInterface by delegating all public
// members from the ClassA.
class ClassB(classA: BaseInterface): BaseInterface by classA {}
object SampleBy {
@JvmStatic fun main(args: Array<String>) {
val classB = ClassB(ClassA())
println(classB.value)
classB.f()
}
}
结果:
property from ClassA
fun from ClassA
参数委托:
// 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