Kotlin标准库函数

news2025/4/19 11:17:54

Kotlin标准库中包含了几个函数,它们的目的就是可以在对象的上下文中执行代码块。当我们调用该Lambda表达式时,它会形成一个临时的作用域。在该范围内,可以访问不带名称的对象,此类函数称为作用域函数。包括:

  • apply函数
  • let函数
  • run函数
  • with函数
  • also函数
  • 区别

官网地址:戳一下

这些函数的不同之处:

函数对象引用返回值扩展函数
letitLambda表达式结果
runthisLambda表达式结果
withthisLambda表达式结果
applythis上下文对象
alsoit上下文对象



下面开始介绍函数…
在这里插入图片描述

apply函数

public inline fun <T> T.apply(block: T.() -> Unit): T

这里,我们把T看做接收者的话,通过T调用apply函数,执行block块函数(lambda表达式)后,最终还是会返回T。

我么可以把它看做是配置类型的函数,返回的还是调用者本身。通过配置一些列相关函数后,返回的还是其本身。

比如,非常适合,Android中SharedPreferences或者集合操作等,会进行一系列配置任务的。

示例


val list = mutableListof().apply{
	add(1)
	add(2)
}


val adam = Person("Adam").apply { 
    age = 20                       // 同this.age = 20
    city = "London"
}
println(adam)

内部通过隐式的this来进行调用

let函数

public inline fun <T, R> T.let(block: (T) -> R): R

把调用用T当做参数,传入block函数中,最终返回block块函数(lambda表达式)的结果

let函数使某个变量作用于lambda表达式里面,使用it关键字引用它。

let跟apply函数区别:

  • let函数会把接受者传入lambda表达式,apply则没有
  • let含税会返回lambda表达式最后一行,apply返回对象本身

示例

 fun testLet() {
        val str = "Hello"
        val result = str.let {
            it.plus(" World")
            "Done"
        }
        Log.d("liu", "result:$result")
    }

let函数执行完后,返回的就是it(最后一行代码执行的结果)

run函数

public inline fun <T, R> T.run(block: T.() -> R): R

run函数,执行的block块函数跟apply函数一样(相当于执行调用者的扩展函数),返回的结果跟let函数一样。

只看作用域。run与apply差不多,不同点:

  • 返回值不同,run函数不返回接收者,它返回的是lambda结果(跟let一样)
  • run函数,可以执行函数引用

示例

  val numbers = mutableListOf("one", "two", "three")
val countEndsWithE = numbers.run { 
    add("four")
    add("five")
    count { it.endsWith("e") }
}
println("There are $countEndsWithE elements that end with e.")

run的lambda内部也是隐式调用了this,并且是返回最后一行代码的执行结果

这里,我们看到需要配置对象,并且带有计算要获取计算最终结果的时候,使用run函数,直接就可以完成了(apply函数无法直接获取计算结果)。

看下run函数,执行函数引用

fun testRun2() {
        val str = "Hello"
        val runResult = str.run(::containHello)

        Log.d("liu", "testRun2:$runResult")
    }

    fun containHello(str: String) = str.contains("Hello")

with函数

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

我们只看with函数后面,发现它跟run函数一模一样。并且,return的也是,执行第一个参数T的block函数块的结果。

所以,这个with函数就是run函数的一个变体,他们功能是一样的,只是调用方式不同。

with是把调用者T放到了第一个参数的位置,run函数是在外面,通过T.run来调用。

示例代码

 fun testWith() {
        val str = "Hello"
        val runResult = with(str) {
            plus("sss")
            plus("ccc")
            "run Done"
        }
        Log.d("liu", "testWith:$runResult")
    }


also函数

public inline fun <T> T.also(block: (T) -> Unit): T 

我们看到also函数跟let函数功能非常像,它也是把接收者作为值参传递给lambda。

只不过,他们的返回结果不同:also函数是返回调用者T对象本身,let返回的是block代码块执行的结果。

既然also返回的是接收者对象,我们可以基于原始接收者对象执行额外的链式调用。

示例代码

val numbers = mutableListOf("one", "two", "three")
numbers
    .also { println("The list elements before adding new one: $it") }
    .add("four")

我们先打印集合,然后,基于返回对象是原始接收者,可以接着添加元素

上面的哪些函数也是作用域函数,除了作用域函数标准库还有takeIf和takeUnless函数。这些函数可以让我们在调用链中嵌入对象状态的检查

takeIf & takeUnless

takeIf 函数需要判断lambda中提供的条件表达式,给出true或false结果。如果是ture,从takeIf返回接收者对象,如果是false,则返回null。反过来,如果对象与谓词不匹配,takeUnless将返回该对象,如果匹配,则返回null。
所以这2个函数可以当做过滤函数来使用。

val number = Random.nextInt(100)

val evenOrNull = number.takeIf { it % 2 == 0 }
val oddOrNull = number.takeUnless { it % 2 == 0 }
println("even: $evenOrNull, odd: $oddOrNull")

这2个函数跟其他函数一起时候时,是非常有用的。

例子,字符串检测

使用标准库函数


fun displaySubstringPosition(input: String, sub: String) {
    input.indexOf(sub).takeIf { it >= 0 }?.let {
        println("The substring $sub is found in $input.")
        println("Its start position is $it.")
    }
}

displaySubstringPosition("010000011", "11")
displaySubstringPosition("010000011", "12")

不使用标准库函数

fun displaySubstringPosition(input: String, sub: String) {
    val index = input.indexOf(sub)
    if (index >= 0) {
        println("The substring $sub is found in $input.")
        println("Its start position is $index.")
    }
}

displaySubstringPosition("010000011", "11")
displaySubstringPosition("010000011", "12")

函数的使用区别

看完上面的函数介绍,我们可以发现。它们都非常的相似。区别就是

  • lambda表达式的上下文对象引用方式(this或it)
  • 返回值不同(上下文对象本身或Lambda执行的结果)

上述函数,每个函数都提供了一种访问上下文对象的方式:this(作为Lambda接收器)、it(作为Lambda参数)

通过 lambda表达式的上下文对象引用方式 区分

run函数,with函数apply函数使用this作为Lambda的上下文对象。在Lambda中使用它们,对象就像在普通函数中一样,可以省略,隐式持有,从而缩短代码。所以,如果我们是在调用其(this)的属性或函数时可以使用它们。

如果忽略这一点的话,函数的差别都不大。

示例代码

val adam = Person("Adam").apply { 
    age = 20                      
    city = "London"
}
println(adam)

let函数,also函数将上下文对象作为Lambda的参数。如果,要将上下文对象当做函数调用的参数时,可以选择它们。

fun getRandomInt(): Int {
    return Random.nextInt(100).also {
        writeToLog("getRandomInt() generated value $it")
    }
}

val i = getRandomInt()
println(i)

当然,我们也可以自定义一个上下文的名字

fun getRandomInt(): Int {
    return Random.nextInt(100).also { value ->
        writeToLog("getRandomInt() generated value $value")
    }
}

val i = getRandomInt()
println(i)

通过返回值区分

  • apply函数,also函数返回的是上下文对象
  • let函数,run函数,with函数,返回的是Lambda表达式的结果

通过返回值,我们可以确认自己需要的是哪类函数了。

  • 返回上下文对象
val numberList = mutableListOf<Double>()
numberList.also { println("Populating the list") }
    .apply {
        add(2.71)
        add(3.14)
        add(1.0)
    }
    .also { println("Sorting the list") }
    .sort()

在使用链式调用的时候,可以选择它们。

  • 返回Lambda表达式的结果

当Lambda表达式的执行结果对我们有用时

val numbers = mutableListOf("one", "two", "three")
val countEndsWithE = numbers.run { 
    add("four")
    add("five")
    count { it.endsWith("e") }
}
println("There are $countEndsWithE elements that end with e.")

当我们需要通过作用域创建通用方法,来做一些事情时

val numbers = mutableListOf("one", "two", "three")
with(numbers) {
    val firstItem = first()
    val lastItem = last()        
    println("First item: $firstItem, last item: $lastItem")
}

Game Over !




在这里插入图片描述

个人感受:看完标准库函数,感觉最重要的区分就是返回值。其它的,仅仅是可以让代码更优雅一点…

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/84630.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java开发才不到3年,来面试开口要25K,面完连10K都不想给

前言 我的好朋友兼大学同学老左家庭经济情况不错&#xff0c;毕业之后没两年自己存了点钱加上家里的支持&#xff0c;自己在杭州开了一家网络公司。由于公司不是很大所以公司大部分的开发人员都是自己面试的&#xff0c;近期公司发展的不错&#xff0c;打算扩招也面试了不少人。…

[l论文解析]Classifier-Free Diffusion Guidance

paper link&#xff1a;https://openreview.net/pdf?idqw8AKxfYbI 文章目录OverviewWhat problem is addressed in the paper?What is the key to the solution?What is the main contribution?Potential fundamental flaws; how this work can be improved?Content关于 c…

Java 字符串 split 的一个反直觉陷阱

最近生产环境遇到一个奇怪的数组下标越界报错&#xff0c;如下图代码所示&#xff0c;我们可以肯定的是 fieldName 变量不为空&#xff08;不是空字符串&#xff0c;也不是 null&#xff09;&#xff0c;但是代码执行到读取 names[0] 变量的时候&#xff0c;抛出了一个 数组下标…

5G无线技术基础自学系列 | 抗衰落技术

素材来源&#xff1a;《5G无线网络规划与优化》 一边学习一边整理内容&#xff0c;并与大家分享&#xff0c;侵权即删&#xff0c;谢谢支持&#xff01; 附上汇总贴&#xff1a;5G无线技术基础自学系列 | 汇总_COCOgsta的博客-CSDN博客 无线信道是随机时变信道&#xff0c;信…

【云计算与大数据技术】文件存储格式行式、列式、GFS、HDFS的讲解(图文解释 超详细)

一、分布式文件系统 文件系统最后都需要以一定的格式存储数据文件&#xff0c;常见的文件存储布局有行式存储、列式存储以及混合式存储三种&#xff0c;不同的类别各有其优缺点和适用的场景&#xff0c;在目前的大数据分析系统中&#xff0c;列式存储和混合式存储方案因其特殊…

mysql 数据库设计三大范式

1. 什么是设计范式 设计表的依据&#xff0c;按照范式设计出来的表&#xff0c;不会出现数据的冗余 数据库的设计范式是数据库设计所需要满足的规范&#xff0c;满足这些规范的数据库是简洁的、结构清晰的&#xff1b;反之则是乱七八糟&#xff0c;不仅会给开发人员制造麻烦&a…

大数据面试之Hive常见题目

大数据面试之Hive常见题目 1. Hive的架构 1、重点四个器&#xff1a;解释器&#xff08;SQL Parser&#xff09;、Driver&#xff1a;编译器&#xff08;Compiler&#xff09;&#xff0c;优化器&#xff08;Optimizer&#xff09;&#xff0c;执行器&#xff08;Executor&…

基于Python+Django的在线学习交流平台

在各学校的教学过程中&#xff0c;直播授课管理是一项非常重要的事情。随着计算机多媒体技术的发展和网络的普及&#xff0c;“基于网络的学习模式”正悄无声息的改变着传统的直播学习模式&#xff0c;“基于网络的直播教学平台”的研究和设计也成为教育技术领域的热点课题。采…

BEPUphysicsint定点数3D物理引擎介绍

帧同步的游戏中如果用物理引擎&#xff0c;为了保证不同设备上的结果一致,需要采用定点数来计算迭代游戏过程中的物理运算。也就是我们通常说的定点数物理引擎(确定性物理引擎)。本系列教程给大家详细的讲解如何在你的项目中内置一个确定性物理引擎。确定性物理引擎我们使用git…

es入门(中)

目录 6.Java api 实现es中的文档管理&#xff08;增删改&#xff09; 6.1 java 客户端简单获取数据 6.2结合spring-boot测试文档查询 配置环境 配置类 测试代码结构 简单的查询 对查询的请求设置参数 异步查询 6.4 结合spring-boot测试文档新增 6.5结合spring-boot…

C语言的预处理器无法先展开宏再拼接符号?可以!

背景 最近接到一个需求&#xff0c;要实现一个脚本&#xff0c;能提取.h文件里定义的所有全局变量的值&#xff0c;这些全局变量都是结构体变量&#xff0c;名字是结构体类型名加场景后缀——每个.h对应的场景都是唯一的&#xff0c;所以.h内所有变量名的后缀一致。 我的解决…

线段树详解(包含加法线段树、乘法线段树及区间根号线段树,简单易懂)

同步发表于洛谷梦回江南 这一篇文章我们将对线段树中的常规操作进行详细的讨论。 以下所提到的复杂度如无特殊说明均为时间复杂度。log⁡\loglog 的底数均为 222。 不开 long long 见祖宗&#xff01; 文章目录第一部 普通线段树一、引入二、优化方案三、懒标记&#xff08;l…

[附源码]Python计算机毕业设计电影网站系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

什么是编程的设计模式,史上最全面Java设计模式总结,看完再也不会忘记

文章目录**9.1 工厂方法模式与抽象工厂模式对比#****9.2 简单工厂模式与单例模式对比#****9.3 简单工厂模式与建造者模式对比#****10.1 装饰器模式与代理模式对比#****10.2 装饰器模式与门面模式对比#****10.3 装饰器模式与适配器模式对比#****10.4 适配器模式与代理模式…

人事管理系统--低代码课程的教学实验/实训教学 (①招聘管理)

人事管理系统是信息系统课程中最为常见的教学场景&#xff0c;对于非计算机专业的学生来说&#xff0c;如何使用低代码&#xff0c;甚至是零代码的方式搭建该系统呢&#xff1f;简道云「人事OA管理」应用包含招聘管理、人员入离职管理、考勤管理、会议室预约、物资进销存管理等…

#3文献学习总结--边缘计算资源分配与任务调度优化

文献&#xff1a;“边缘计算资源分配与任务调度优化综述 ” 1、系统模型“云-边-端” 第 1 层是物联网层&#xff0c;传感器、处理器根据应用需求感知、测量和收集原始数据&#xff0c;在本地处理大量数据或将其上传至计算节点。 第 2 层是边缘计算层&#xff0c;位于互联网边…

rollup打包vue组件

rollup安装与使用 npm i rollup -g # 全局安装 npm i rollup -D # 项目本地安装rollup配置 import vue from rollup-plugin-vue import typescript from rollup-plugin-typescript2 import postcss from rollup-plugin-postcss; import cssnano from cssnano i…

2022华为全球校园AI算法精英赛:季军方案!

Datawhale干货 作者&#xff1a;鲤鱼&#xff0c;西安交通大学&#xff0c;人工智能学院笔者鲤鱼&#xff0c;是西安交通大学人工智能学院的一名研究生&#xff0c;在2022华为全球校园AI算法精英赛的赛道二取得了季军的成绩。初赛阶段一直名列A榜的榜首&#xff0c;复赛前几天也…

zabbix6.0安装教程(二):Zabbix6.0安装最佳实践

zabbix6.0安装教程&#xff08;二&#xff09;&#xff1a;Zabbix6.0安装最佳实践 目录概述一、Access control1.Zabbix agent 的安全用户2.UTF-8 编码二、Zabbix Security Advisories and CVE database1.为 Zabbix 前端设置 SSL三、Web server hardening1.在 URL 的根目录上启…

[附源码]Python计算机毕业设计SSM基于的开放式实验室预约系统(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…