“ by”关键字在科特林有什么作用?


Answers:


74

Kotlin参考资料中,您可以找到的两个用途by,第一个是Delegated Properties,它是您在上方的用途:

有某些常见的属性,尽管我们可以在需要时手动实现它们,但一劳永逸地实现并将其放入库中会非常好。示例包括惰性属性:仅在首次访问时才计算值,可观察的属性:侦听器会收到有关对此属性的更改的通知,将属性存储在映射中,而不是分别存储在单独的字段中。

在这里,您将getter / setter委托给另一个工作的类,该类可以包含通用代码。作为另一个示例,用于Kotlin的某些依赖项注入器通过委派getter从依赖项注入引擎管理的实例注册表中接收值来支持此模型。

接口/类代表团是其他用途:

事实证明,委托模式是实现继承的一个很好的选择,并且Kotlin支持它本来需要零样板代码。派生的类可以从接口Base继承,并将其所有公共方法委托给指定的对象

在这里,您可以将接口委派给另一个实现,因此实现类仅需要覆盖其要更改的内容,而其余方法将委派回完整的实现。

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

Kotlin语言参考涵盖了这两个方面,从此处开始介绍该语言的基本主题。


83

简而言之,您可以理解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那里没有)。


18

在此处输入图片说明

语法为:

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

by之后的表达式是委托

如果尝试访问属性p的值,换句话说,如果调用属性p的get()方法,则使用DelegategetValue()方法调用实例。

如果尝试设置属性p的值,换句话说,如果调用属性p的set()方法,则将调用Delegate实例的setValue()方法。


5

财产委派:

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.