当前位置:网站首页> Kotlin1.6.20新功能Context Receivers使用技巧揭秘
Kotlin1.6.20新功能Context Receivers使用技巧揭秘
2022-06-22 19:06:00 【1024问】
前言
扩展函数的局限性
什么是 Context Receivers
如何使用 Context Receivers
引入 Context Receivers 导致可读性问题
Context Receivers 应用范围及注意事项
总结
前言这篇文章我们一起来聊一下 Kotlin 1.6.20 的新功能 Context Receivers,来看看它为我们解决了什么问题。
通过这篇文章将会学习到以下内容:
扩展函数的局限性
什么是 Context Receivers,以及如何使用
Context Receivers 解决了什么问题
引入 Context Receivers 会带来新的问题,我们如何解决
Context Receivers 应用范围及注意事项
扩展函数的局限性在 Kotlin 中接受者只能应用在扩展函数或者带接受者 lambda 表达式中, 如下所示。
class Context { var density = 0f}// 扩展函数inline fun Context.px2dp(value: Int): Float = value.toFloat() / density接受者是 fun 关键字之后和点之前的类型 Context,这里隐藏了两个知识点。
我们可以像调用内部函数一样,调用扩展函数 px2dp(),通常结合 Kotlin 作用域函数 with , run , apply 等等一起使用。
with(Context()) { px2dp(100)}在扩展函数内部,我们可以使用 this 关键字,或者隐藏关键字隐式访问内部的成员函数,但是我们不能访问私有成员
扩展函数使用起来很方便,我们可以对系统或者第三方库进行扩展,但是也有局限性。
只能定义一个接受者,因此限制了它的可组合性,如果有多个接受者只能当做参数传递。比如我们调用 px2dp() 方法的同时,往 logcat 和 file 中写入日志。
class LogContext { fun logcat(message: Any){}}class FileContext { fun writeFile(message: Any) {}}fun printf(logContext: LogContext, fileContext: FileContext) { with(Context()) { val dp = px2dp(100) logContext.logcat("print ${dp} in logcat") fileContext.writeFile("write ${dp} in file") }}在 Kotlin 中接受者只能应用在扩展函数或者带接受者 lambda 表达式中,却不能在普通函数中使用,失去了灵活性
Context Receivers 的出现带来新的可能性,它通过了组合的方式,将多个上下文接受者合并在一起,灵活性更高,应用范围更广。
什么是 Context ReceiversContext Receivers 用于表示一个基本约束,即在某些情况下需要在某些范围内才能完成的事情,它更加的灵活,可以通过组合的方式,组织上下文,将系统或者第三方类组合在一起,实现更多的功能。
如果想在项目中使用 Context Receivers,需要将 Kotlin 插件升级到 1.6.20 ,并且在项目中开启才可以使用。
plugins { id 'org.jetbrains.kotlin.jvm' version '1.6.20'}// ......kotlinOptions { freeCompilerArgs = ["-Xcontext-receivers"]}如何使用 Context Receivers当我们完成上述配置之后,就可以在项目中使用 Context Receivers,现在我们将上面的案例改造一下。
context(LogContext, FileContext)fun printf() { with(Context()) { val dp = px2dp(100) logContext.logcat("print ${dp} in logcat") fileContext.writeFile("write ${dp} in file") }}我们在 printf() 函数上,使用 context() 关键字,在 context() 关键字括号中,声明上下文接收者类型的列表,多个类型用逗号分隔。但是列出的类型不允许重复,它们之间不允许有子类型关系。
通过 context() 关键字来限制它的作用范围,在这个函数中,我们可以调用上下文 LogContext 、 FileContext 内部的方法,但是使用的时候,只能通过 Kotlin 作用域函数嵌套来传递多个接受者,也许在未来可能会提供更加优雅的方式。
with(LogContext()) { with(FileContext()) { printf("I am DHL") }}引入 Context Receivers 导致可读性问题如果我们在 LogContext 和 FileContext 中声明了多个相同名字的变量或者函数,我们只能通过 [email protected] 语句来解决这个问题。
context(LogContext, FileContext)fun printf(message: String) { logcat("print message in logcat ${[email protected]}") writeFile("write message in file ${[email protected]}")}正如你所见,在 LogContext 和 FileContext 中都有一个名为 name 的变量,我们只能通过 [email protected] 语句来访问,但是这样会引入一个新的问题,如果有大量的同名的变量或者函数,会导致 this 关键字分散到处都是,造成可读性很差。所以我们可以通过接口隔离的方式,来解决这个问题。
interface LogContextInterface{ val logContext:LogContext}interface FileContextInterface{ val fileContext:FileContext}context(LogContextInterface, FileContextInterface)fun printf(message: String) { logContext.logcat("print message in logcat ${logContext.name}") fileContext.writeFile("write message in file ${fileContext.name}")}通过接口隔离的方式,我们就可以解决 this 关键字导致的可读性差的问题,使用的时候需要实例化接口。
val logContext = object : LogContextInterface { override val logContext: LogContext = LogContext()}val fileContext = object : FileContextInterface { override val fileContext: FileContext = FileContext()}with(logContext) { with(fileContext) { printf("I am DHL") }}Context Receivers 应用范围及注意事项当我们重写带有上下文接受者的函数时,必须声明为相同类型的上下文接受者。
interface Canvasinterface Shape { context(Canvas) fun draw()}class Circle : Shape { context(Canvas) override fun draw() { }}我们重写了 draw() 函数,声明的上下文接受者必须是相同的,Context Receivers 不仅可以作用在扩展函数、普通函数上,而且还可以作用在类上。
context(LogContextInterface, FileContextInterface)class LogHelp{ fun printf(message: String) { logContext.logcat("print message in logcat ${logContext.name}") fileContext.writeFile("write message in file ${fileContext.name}") }}在类 LogHelp 上使用了 context() 关键字,我们就可以在 LogHelp 范围内任意的地方使用 LogContext 或者 FileContex。
val logHelp = with(logContext) { with(fileContext) { LogHelp() }}logHelp.printf("I am DHL")Context Receivers 除了作用在扩展函数、普通函数、类上,还可以作用在属性 getter 和 setter 以及 lambda 表达式上。
context(View)val Int.dp get() = this.toFloat().dp// lambda 表达式fun save(block: context(LogContextInterface) () -> Unit) {}最后我们来看一下,来自社区 Context Receivers 实践的案例,扩展 Json 工具类。
fun json(build: JSONObject.() -> Unit) = JSONObject().apply { build() }context(JSONObject)infix fun String.by(build: JSONObject.() -> Unit) = put(this, JSONObject().build())context(JSONObject)infix fun String.by(value: Any) = put(this, value)fun main() { val json = json { "name" by "Kotlin" "age" by 10 "creator" by { "name" by "JetBrains" "age" by "21" } }}总结Context Receivers 提供一个基本的约束,可以在指定范围内,通过组合的方式实现更多的功能
Context Receivers 可以作用在扩展函数、普通函数、类、属性 getter 和 setter 、 lambda 表达式
Context Receivers 允许在不需要继承的情况,通过组合的方式,组织上下文,将系统或者第三方类组合在一起,实现更多的功能
通过 context() 关键字声明,在 context() 关键字括号中,声明上下文接收者类型的列表,多个类型用逗号分隔
如果大量使用 this 关键字会导致可读性变差,我们可以通过接口隔离的方式来解决这个问题
当我们重写带有上下文接受者的函数时,必须声明为相同类型的上下文接受者
以上就是Kotlin1.6.20功能Context Receivers使用技巧揭秘的详细内容,更多关于Kotlin1.6.20功能Context Receivers的资料请关注软件开发网其它相关文章!
边栏推荐
- Web technology sharing | [Gaode map] to realize customized track playback
- B tree code (C language)
- EasyDSS问题及解决方案汇总
- 智能计算之神经网络(Hopfield网络-DHNN,CHNN )介绍
- Random talk about redis source code 122
- Random talk about redis source code onehundredandtwenty
- 什么?你居然不会微信分身
- AAAI 2022 | 传统GAN修改后可解释,并保证卷积核可解释性和生成图像真实性
- leetcode.11 --- 盛最多水的容器
- client-go gin的简单整合十一-Delete
猜你喜欢

Zabbix学习笔记(三十七)

请你描述下从浏览器上输入一个url到呈现出页面的整个过程。

完全背包如何考虑排列问题
![[in depth understanding of tcaplus DB technology] getting started tcaplus SQL driver](/img/2b/3ab5e247ac103728b4d3579c3c5468.png)
[in depth understanding of tcaplus DB technology] getting started tcaplus SQL driver

软件上线前为什么要做性能测试?软件性能测试机构怎么找

web技术分享| 【高德地图】实现自定义的轨迹回放

Introduction to async profiler

Containerd容器运行时(2):yum安装与二进制安装,哪个更适合你?

【深入理解TcaplusDB技术】查看TcaplusDB线上运行情况

Possible security vulnerabilities in NFT
随机推荐
智能計算之神經網絡(BP)介紹
【Proteus仿真】74LS138译码器流水灯
Multi transactions in redis
B tree code (C language)
Using span method to realize row merging of multi-layer table data
Understand the index of like in MySQL
基于Sentinel的高可用限流系统的Grafana报表展示
Nestjs 集成 config module 与 nacos 实现配置化统一
Gossip about redis source code 121
[in depth understanding of tcaplus DB technology] getting started tcaplus SQL driver
Merge sort (recursive and iterative Implementation)
web技术分享| 【高德地图】实现自定义的轨迹回放
Introduction of neural network (BP) in Intelligent Computing
Connect function usage of socket
[graduation season] step by step? Thinking about four years of University by an automation er
DynamicDatabaseSource,在应用端支持数据库的主从
【深入理解TcaplusDB技术】TcaplusDB 表管理——清理表
三维天地助力实验室夯实完整质量体系管理
市场开始降温,对NFT 是坏事么?
Bubble sort, select sort, direct insert sort