在为android开发时,我有时会遇到这样的情况:
var someModel: someViewModel by notNullAndObservable { vm ->
...
}
我不明白by关键字的意义是什么。
在为android开发时,我有时会遇到这样的情况:
var someModel: someViewModel by notNullAndObservable { vm ->
...
}
我不明白by关键字的意义是什么。
当前回答
简单地说,您可以通过提供的关键字来理解。
从属性消费者的角度来看,val是具有getter (get)的东西,var是具有getter和setter (get, set)的东西。对于每个var属性,都有一个默认的get和set方法提供程序,我们不需要显式地指定。
但是,当使用by关键字时,你是在声明这个getter/getter&setter是在其他地方提供的(即它是委托的)。它是由by后面的函数提供的。
因此,不是使用这个内置的get和set方法,而是将该任务委托给一些显式函数。
一个非常常见的例子是by lazy for 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)
其他回答
语法为:
val/var <property name>: <Type> by <expression>.
by后面的表达式是委托
如果我们试图访问属性p的值,换句话说,如果我们调用属性p的get()方法,则会调用Delegate实例的getValue()方法。
如果我们试图设置属性p的值,换句话说,如果我们调用属性p的set()方法,则会调用Delegate实例的setValue()方法。
财产委托:
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
简单地说,您可以通过提供的关键字来理解。
从属性消费者的角度来看,val是具有getter (get)的东西,var是具有getter和setter (get, set)的东西。对于每个var属性,都有一个默认的get和set方法提供程序,我们不需要显式地指定。
但是,当使用by关键字时,你是在声明这个getter/getter&setter是在其他地方提供的(即它是委托的)。它是由by后面的函数提供的。
因此,不是使用这个内置的get和set方法,而是将该任务委托给一些显式函数。
一个非常常见的例子是by lazy for 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)
在Kotlin引用中,你会发现by的两种用法,第一个是委托属性,这是你上面的用法:
有一些常见的属性类型,尽管我们可以在每次需要时手动实现它们,但一次性实现并放入库中会非常好。例如惰性属性:值只在第一次访问时计算, 可观察属性:监听器得到关于该属性更改的通知, 将属性存储在一个映射中,而不是在每个单独的字段中。
在这里,您将getter/setter委托给另一个类,这个类可以完成这项工作,并且可以包含公共代码。另一个例子是,Kotlin的一些依赖注入器通过委托getter从依赖注入引擎管理的实例注册中心接收值来支持这个模型。
接口/类委托是另一个用途:
委托模式已被证明是实现继承的一个很好的替代方案,并且Kotlin支持它,它本身不需要任何样板代码。派生类可以继承接口基,并将其所有公共方法委托给指定的对象
在这里,您可以将接口委托给另一个实现,这样实现类只需要覆盖它想要更改的内容,而其余方法则委托给更完整的实现。
一个活生生的例子是Klutter Readonly/Immutable集合,它们实际上只是将特定的集合接口委托给另一个类,然后覆盖在只读实现中需要不同的任何内容。节省了大量的工作,不必手动委托所有其他方法。
这两个都在Kotlin语言参考中涵盖,从该语言的基本主题开始。