在为Android开发时,有时会遇到如下所示的内容:
var someModel: someViewModel by notNullAndObservable { vm ->
...
}
我不明白by
关键字的意义是什么。
Answers:
在Kotlin参考资料中,您可以找到的两个用途by
,第一个是Delegated Properties,它是您在上方的用途:
有某些常见的属性,尽管我们可以在需要时手动实现它们,但一劳永逸地实现并将其放入库中会非常好。示例包括惰性属性:仅在首次访问时才计算值,可观察的属性:侦听器会收到有关对此属性的更改的通知,将属性存储在映射中,而不是分别存储在单独的字段中。
在这里,您将getter / setter委托给另一个工作的类,该类可以包含通用代码。作为另一个示例,用于Kotlin的某些依赖项注入器通过委派getter从依赖项注入引擎管理的实例注册表中接收值来支持此模型。
和接口/类代表团是其他用途:
事实证明,委托模式是实现继承的一个很好的选择,并且Kotlin支持它本来需要零样板代码。派生的类可以从接口Base继承,并将其所有公共方法委托给指定的对象
在这里,您可以将接口委派给另一个实现,因此实现类仅需要覆盖其要更改的内容,而其余方法将委派回完整的实现。
一个生动的例子是Klutter只读/不可变集合,其中它们实际上只是将特定的集合接口委托给另一个类,然后覆盖只读实现中需要与众不同的任何内容。无需手动委派所有其他方法,从而节省了大量工作。
Kotlin语言参考涵盖了这两个方面,从此处开始介绍该语言的基本主题。
简而言之,您可以理解by
所提供的关键字。
从财产消费者的角度来看,val
是具有getter(获取)var
的东西,是具有getter和setter(获取,设置)的东西。对于每个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(这是隐式的,所以by
那里没有)。
财产委派:
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