Kotlin 委托

定义

有时候我们需要办成某件事但又不想自己做时,可以将其交给别人做,这其实就是一种委托。Kotlin 中可以使用by关键字声明委托。

继承/实现的委托

某个类ClassA想要实现一个接口MyInterface,但是发现接口中的抽象方法非常多,全部实现非常困难。巧的是我们已经有另一个类ClassB(或者该接口的一个对象)实现了该接口,此时我们可以将ClassA的实现MyInterface的工作委托给ClassB

interface MyInterface {
    // 超多抽象方法
    fun example()
}


class ClassB: MyInterface {
    // 超多抽象方法的实现
    override fun example() = print("ClassB 实现")
}


class ClassA(classB: ClassB): MyInterface by classB {
    // ClassA 不需要自己实现 MyInterface 的方法
}


fun main() {
    val classB = ClassB()
    ClassA(classB).example()
}
ClassB 实现

如果我们发现ClassB中的某个方法的实现并不是ClassA想要的,还可以在ClassA中声明对MyInterface方法的重写,此时如果调用ClassAexample则会调用新重写的这个:

interface MyInterface {
    // 超多抽象方法
    fun example()
}


class ClassB: MyInterface {
    // 超多抽象方法的实现
    override fun example() = print("ClassB 实现")
}


class ClassA(classB: ClassB): MyInterface by classB {
    override fun example() = print("ClassA 实现")
}


fun main() {
    val classB = ClassB()
    ClassA(classB).example()
}
ClassA 实现

属性的委托

委托给对象

我们可以将属性 getter 和 setter 委托给某一个对象,此时会将getset函数委托给类的getValuesetValue声明。

val修饰的不可变变量只有 getter,因此只会将get委托给getValue

最常见的是Lazy,我们可以使用函数lazy(后边的 lambda 需要返回一个值作为变量的初始值,该值的类型会作为变量类型)生成一个Lazy对象,并将某一个变量委托给它:

val name = "Kotlin".also { println("name 初始化") }
val lazyName by lazy { println("lazyName 初始化"); "Kotlin" }

val version = 2.also { println("version 初始化") }
val lazyVersion by lazy { println("lazyVersion 初始化"); 2 }

fun main() {
    // 在运行时,name 就被初始化了
    // 而委托给 Lazy 的 lazyName 没有被初始化

    // 在运行时,version 就被初始化了
    // 只有在访问值时,lazyVersion 才会被初始化
    lazyVersion
}
name 初始化
version 初始化
lazyVersion 初始化

委托给另一个变量

此时委托变量前需要加双冒号::,事实上,::name会返回一个KMutableProperty0<String>对象,所以这是还是将变量委托给了对象。比较特殊的是,该对象并没有声明getValuesetValue,委托将交给其 getter 和 setter。

二者的 getter 和 setter 实际上已经绑定在一起了,当其中一个的值改变,另一个也会跟着变。

var name: String = "K1"


fun main() {
    var delegateName by ::name
    
    // 打印 name 并改变 delegateName 也是同样的结果
    println(delegateName)
    name = "K2"
    print(delegateName)
}
K1
K2

能将可变变量var委托给不可变变量val,因为val没有 setter。

val name: String = "K1"


fun main() {
    // 这是错误的
    // var delegateName by ::name
}

自定义可委托类

得益于 IDEA 自动补全,我们可以直接写出委托关系var value by MyClass(),鼠标悬停(或者光标置于标红处,按键盘Alt+Enter),点击创建getValuesetValue,并加以修改即可。其中,参数名可以自定义。

生成的nothing(第1个参数)一般是叫thisRef,它的类型是该变量所有者的类型(例如某个类的成员变量,其所有者是该类)。
这里Nothing?则表示没有所有者。对于其他类型,如果加了?,则所有变量都可以委托,如果不加,则只有变量的所有者为指定类型可以委托。

property中则包含了委托变量的属性,例如property.name可以获取到变量名。其类型必须为KProperty<*>

getValue的返回值一般需要指明为所要获取值的类型,这里把MyClass.value返回。
setValue传入的第3个参数则是要赋的值,这里把值给MyClass.value

import kotlin.reflect.KProperty


class MyClass {
    private var value = "MyClass"


    operator fun getValue(thisRef: Nothing?, property: KProperty<*>): String {
        println("getValue")
        return value
    }


    operator fun setValue(thisRef: Nothing?, property: KProperty<*>, s: String) {
        println("setValue")
        value = s
    }
}


fun main() {
    var value by MyClass()
    println(value)
    value = "Hello"
    print(value)
}
getValue
MyClass
setValue
getValue
Hello
  • 21
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
DataStore是一个新的异步API,用于在Kotlin中存储和读取数据。它使用Kotlin协程和Flow来实现异步操作,并在单独的线程上运行,从而保证了线程安全性。DataStore提供了结构化的错误处理、类型安全以及存储自定义复杂或大型数据类对象的支持。 要使用DataStore,首先需要获取DataStore对象。可以通过使用Kotlin委托来实现,具体如下所示: ```kotlin private val settingsDataStore by preferencesDataStore(name = "app_settings") ``` 在上述代码中,`settingsDataStore`是一个DataStore对象,它使用了`preferencesDataStore`委托来获取。`name`参数指定了DataStore的名称,可以是任何字符串,例如"app_settings"或包名称等。 一旦获取了DataStore对象,就可以使用它来读取和写入数据。以下是一些示例代码: ```kotlin // 写入数据 settingsDataStore.edit { settings -> settings[KEY_NAME] = "John" settings[KEY_AGE] = 25 } // 读取数据 val nameFlow: Flow<String?> = settingsDataStore.data.map { settings -> settings[KEY_NAME] } // 监听数据变化 settingsDataStore.data .map { settings -> settings[KEY_AGE] } .distinctUntilChanged() .onEach { age -> // 处理数据变化 } .launchIn(lifecycleScope) ``` 上述代码中,`edit`函数用于写入数据,`data`属性用于读取数据。可以使用`map`和`distinctUntilChanged`等函数对数据进行转换和过滤。`launchIn`函数用于在协程作用域中启动数据监听。 总结一下,DataStore是一个用于存储和读取数据的异步API,它提供了线程安全、结构化的错误处理、类型安全以及存储自定义复杂或大型数据类对象的支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值