Kotin 语法糖

本文详细介绍了Kotlin中的语法糖,特别是apply、run、with、let和also等内置函数的使用、参数和返回值特点,以及它们背后的原理。作者还探讨了这些函数如何利用Kotlin的高阶函数特性来简化代码并控制方法行为。
摘要由CSDN通过智能技术生成

前言

Kotlin 语法糖的总结和原理分析。

Kotlin 有很多实用的语法糖,比如扩展函数、object 单例、apply/run/with 等内置函数,对于开发者来说非常的友好的方便。简单梳理和总结包括但不限于上述这些语法糖的内容。

Syntactic Sugar

内置函数

kotlin-stdlib 内的 Standard.kt 文件内定义了几个比较实用的顶层函数 比如 apply/with/run/let/also 等,这几个函数的功能比较相似,但又略微有些差异,在此梳理一下。

  • 示例

fun main() {
    val sugar = Sugar("mike", 21, true)
    printInfo(sugar)

    val letResult = sugar.let {
        it.name = "let"
        it.age = 9
    }
    printInfo(letResult)

    val alsoResult = sugar.also {
        it.name = "also"
        it.age = 13
    }
    printInfo(alsoResult)

    val withResult = with(sugar) {
        name = "with"
        age = 10
    }
    printInfo(withResult)

    val runResult = sugar.run {
        name = "run"
        age = 11
    }
    printInfo(runResult)

    val applyResult = sugar.apply {
        name = "apply"
        age = 12
    }
    printInfo(applyResult)
}

output

  • 返回值
Sugar(name=mike, age=21, happy=true) : com.ext.Sugar

kotlin.Unit : kotlin.Unit  // let

Sugar(name=also, age=13, happy=true) : com.ext.Sugar // also

kotlin.Unit : kotlin.Unit  // with

kotlin.Unit : kotlin.Unit // run 

Sugar(name=apply, age=12, happy=true) : com.ext.Sugar // apply

首先从返回结果,可以看到,默认情况下 apply 和 also 返回的都是当前对象,let/with/run 返回的是 kotlin.Unit ,也就是在 Lamdba 表达式中如果没有显示的在最后一行写返回值,那么 kotlin.Unit 就是返回值,可以理解为 Java 中的 Void。

  • 参数

在这里插入图片描述

在这里插入图片描述

其次从 lambda 表达式的参数可以看出,it 和 also 都是 it ,剩下的 run/with/apply 都是 this 。其实 run 和 with 是的表现是完全一致的,只是调用方式不同而已,run 只需要一个参数,而 with 需要把接受者和 lambda 同时传入。

类型参数返回值
letitlambda 表达式最后一行,默认为 kotlin.Unit
alsoit接受者,即调用方法的对象
applythis接受者,即调用方法的对象
withthislambda 表达式最后一行,默认为 kotlin.Unit
runthislambda 表达式最后一行,默认为 kotlin.Unit
原理剖析

总的来说,这几个内置函数的实现是高度相似的,都是使用了 Kotlin 高阶函数的特性。但是他又是如何实现这些微妙的差异的那?我们可以对比一下 letalso

public inline fun <T, R> T.let(block: (T) -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block(this)
}

public inline fun <T> T.also(block: (T) -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block(this)
    return this
}

  • 可以看到 block: (T) -> R block 函数的参数类型就是 T,也就是调用者。因此 lambda 表达式的参数名称就是 it
  • 再看返回值 let 直接返回了 block 函数的运行结果,而这个 block 函数就是我们调用时传入的 lambda 表达式,因此其执行结果就是整个函数的结果。而 also block 函数时返回值就是 Unit ,也就是说 lambda 表达式的结果是被忽略的。这里可以认为调用 block 只是为了执行一项操作,而实际返回是 this

再来看看为什么有时候参数是 it ,有时候又是 this 呢? 可以对比一下 alsoapply

public inline fun <T> T.also(block: (T) -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block(this)
    return this
}

public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}

  • 这里的关键就是 block 函数的定义。 注意到 apply 中 block T.() -> Unit 的写法,可以看到这里明确了当前函数执行的类型,同时参数为空;可以试一下,这种情况下,定义参数是没有意义的。
  public fun <T> T.apply1(block: T.(Int) -> Unit): T {
      block(1)
      return this
  }

比如这里,虽然定义了 block 的参数为 Int 类型,但是因为应明确定义了 block 函数是在 T 类型执行,因此实际调用时也无法传递这个参数,因此这里实现时也无法获取到具体的参数值 。

小结

Kotlin 高阶函数是平日开发中最常用的功能,使用高阶函数可以实现代码逻辑的简化和封装,最重要的一点就是把函数当参数的特性,让方法的行为能够被另外一个方法的行为控制,甚至是实现套娃。一些比较常见的三方库比如 LeakCanary/OkHttp 等使用 Kotlin 重写之后也是大量使用了高阶函数。而 let/also/apply/run/with 这几个常用的内置函数,就高阶函数的定义做了最好的师范。

最后

为了帮助大家能更系统的学习Kotlin,在这里分享这份全网最全的Kotlin入门教程指南,有需要完整版的朋友扫描下方二维码!!!

内容展示

Kotlin入门教程指南

  • 前言在这里插入图片描述

1.概述

  • 1.1使用 Kotlin 进行服务器端开发
  • 1.2 使用 Kotlin 进行 Android 开发
  • 1.3 Kotlin JavaScript 概述
  • 1.4 Kotlin/Native 用于原生开发
  • 1.5 用于异步编程等场景的协程
  • 1.6 Kotlin 1.1 的新特性
  • 1.7 Kotlin 1.2 的新特性
  • 1.8 Kotlin 1.3 的新特性在这里插入图片描述

2.开始

  • 2.1 基本语法
  • 2.2 习惯用法
  • 2.3 编码规范在这里插入图片描述

3.基础

  • 3.1 基本类型
  • 3.2 包
  • 3.3 控制流:if、when、for、while
  • 3.4 返回和跳转在这里插入图片描述

4.类与对象

  • 4.1 类与继承
  • 4.2 属性与字段
  • 4.3 接口
  • 4.4 可见性修饰符
  • 4.5 扩展
  • 4.6 数据类
  • 在这里插入图片描述

5.函数与Lambda表达式

  • 5.1 函数
  • 5.2 高阶函数与lambda表达式
  • 5.3 内联函数在这里插入图片描述

6.其他

  • 6.1 解构声明
  • 6.2 集合:List、Set、Map
  • 6.3 区间
  • 6.4 类型的检查与转换“is”与“as”
  • 6.5 This 表达式
  • 6.6 相等性
  • 在这里插入图片描述

7.Java互操作与JavaScript

  • 7.1 在 Kotlin 中调用 Java 代码
  • 7.2 Java 中调用 Kotlin
  • 7.3 JavaScript 动态类型
  • 7.4 Kotlin 中调用 JavaScript
  • 7.5 JavaScript 中调用 Kotlin
  • 7.6 JavaScript 模块
  • 7.7 JavaScript 反射
  • 7.8 JavaScript DCE在这里插入图片描述

8.协程

  • 8.1 协程基础
  • 8.2 取消与超时
  • 8.3 通道 (实验性的)
  • 8.4 组合挂起函数
  • 8.5 协程上下文与调度器
  • 8.6 异常处理
  • 8.7 select 表达式(实验性的)
  • 8.8 共享的可变状态与并发在这里插入图片描述

9.工具

  • 9.1 编写 Kotlin 代码文档
  • 9.2 Kotlin 注解处理
  • 9.3 使用 Gradle
  • 9.4 使用 Maven
  • 9.5 使用 Ant
  • 9.6 Kotlin 与 OSGi
  • 9.7 编译器插件
  • 9.8 不同组件的稳定性在这里插入图片描述

常见问题概述

  • FAQ
  • 与Java语言比较
  • 与Scala比较【官方已删除】在这里插入图片描述
完整学习文档可以扫描下方二维码免费领取!!
  • 19
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值