网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
Kotlin 在 1.6.20 版本中加入了 Context Receivers 的想法。在这篇文章中,我想玩弄它们以了解它们的用处。
请注意,如果您想一起玩,则需要使用context-receivers标志进行编译。
Context Receivers背后的主要思想是将附加参数传递给函数,而无需显式执行。
简化的模型样本
让我们从一个简单的例子开始来展示它是如何工作的。我们想对两个 ba 之间的简单传输操作进行建模让我们从一个简单的例子开始来展示它是如何工作的。我们想模拟两个银行账户之间的简单转账操作。账户余额存储在数据库中,相应的贷记/还款操作必须是交易性的。
让我们专注于AccountService.transfer()功能。它需要一个Transaction包含多个操作的实例:
class AccountService {
fun transfer(tx: Transaction, vararg operations: () -> Unit) {
tx.start()
try {
operations.forEach { it.invoke() }
tx.commit()
} catch (e: Exception) {
tx.rollback()
}
}
}
我们可以将上面的代码称为:
val service = AccountService()
val transaction = Transaction()
val repo = AccountRepo()
service.transfer(
transaction,
{ repo.credit(account1, 10.5) },
{ repo.debit(account2, 10.5) }
)
使用扩展函数改进代码
我们可以利用扩展函数对上面的代码稍加改进。我们可以将后者迁移到扩展函数,而不是将其定义Transaction为函数的参数。transfer()
class AccountService {
fun Transaction.transfer(vararg operations: () -> Unit) {
start() // 1
try {
operations.forEach { it.invoke() }
commit() // 1
} catch (e: Exception) {
rollback() // 1
}
}
}
- 隐式this引用Transaction对象
在 的上下文中AccountService,我们现在可以transfer()在现有的 上调用函数Transaction。
with(service) { // 1
transaction.transfer( // 2
{ repo.credit(account1, 10.5) },
{ repo.debit(account2, 10.5) }
)
}
- 将service实例纳入范围
- 所以调用对象是有效transfer的transaction
可以从两个不同的角度分析新的调用代码:
- 输入的原始字符数更少、更简洁
- 但是,语义完全不同。新代码意味着在的Context中AccountService,我们可以调用transfer()现有Transaction对象。
我认为语义是错误的;它应该是相反的。它应该是相反的。在的Context中Transaction,我们应该能够调用transfer()现有AccountService对象:
with(transaction) {
service.transfer(
{ repo.credit(account1, 10.5) },
{ repo.debit(account2, 10.5) }
)
}
恕我直言,与错误语义的成本相比,简洁的价值很小。不幸的是,对于当前的语言结构,修复语义意味着我们需要将transfer()函数移动到Transaction. 这将是糟糕的建模,因为传输是服务的责任。
Context Receivers
正如我在介绍中提到的,Context Receivers背后的想法是以某种方式“传递”函数参数,而不是明确地说明它们。
context(Foo, Bar, Baz)
fun myfunction() {}
要调用这样的函数,需要将每个Context类型的对象带入“范围”。我们可以通过with函数来实现:
val foo = Foo()
val bar = Bar()
val baz = Baz()
with(foo) { // 1
with(bar) { // 2
with (baz) { // 3
myfunction() // 4
}
}
}
- 引入foo范围
- 引入bar范围
- 引入baz范围
- 调用函数
虽然上面的代码可以编译,但它只有在我们使用Context对象时才适用。调用语法与带有接收器的 lambda 之一相同:
context(Foo, Bar, Baz)
fun myfunction() {
println(this@Foo)
println(this@Bar)
println(this@Baz)
}
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!**
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新