by'关键字做在Kotlin?

在为android开发时,我有时会遇到这样的情况:

var someModel: someViewModel by notNullAndObservable { vm ->
...
}

我不明白by关键字的意义是什么。

52934 次浏览

芬兰湾的科特林参考中,你会发现by有两种用法,第一个是委托的属性,也就是上面的用法:

有一些常见的属性类型,尽管我们可以在每次需要时手动实现它们,但一次性实现并放入库中会非常好。例如惰性属性:值只在第一次访问时计算, 可观察属性:监听器得到关于该属性更改的通知, 将属性存储在一个映射中,而不是在每个单独的字段中

在这里,您将getter/setter委托给另一个类,这个类可以完成这项工作,并且可以包含公共代码。另一个例子是,Kotlin的一些依赖注入器通过委托getter从依赖注入引擎管理的实例注册中心接收值来支持这个模型。

接口/类代表团是另一种用法:

委托模式已被证明是实现继承的一个很好的替代方案,并且Kotlin支持它,它本身不需要任何样板代码。派生类可以继承接口基,并将其所有公共方法委托给指定的对象

在这里,您可以将接口委托给另一个实现,这样实现类只需要覆盖它想要更改的内容,而其余方法则委托给更完整的实现。

一个活生生的例子是Klutter只读/不可变集合,它们实际上只是将特定的集合接口委托给另一个类,然后覆盖在只读实现中需要不同的任何内容。节省了大量的工作,不必手动委托所有其他方法。

这两个都包含在Kotlin语言引用,从语言的基本主题开始。

简单来说,你可以将by关键字理解为提供的< em > < / em >

从属性消费者的角度来看,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类,我提供SomeInterface接口的函数,这些函数是由SomeImplementation提供的。 我将自己实现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

enter image description here

语法为:

val/var <property name>: <Type> by <expression>.

by后面的表达式是委托

如果我们试图访问属性p的值,换句话说,如果我们调用属性pget ()方法,则会调用委托实例的getValue ()方法。

如果我们试图设置属性p的值,换句话说,如果我们调用属性p设置()方法,则会调用委托实例的setValue ()方法。