Kotlin理解内置函数
目录
- 一 内置函数
- 1.1 apply 函数
- 1.2 let 函数
- 1.3 run函数
- 1.4 with函数
- 1.5 also函数
- 1.6 takeIf函数
- 1.7 takeUnless函数
- 1.8 总结
Kotlin
内置函数包括:let
、run
、with
、apply
、also
,这些函数都是在Any
类中定义的扩展函数,所以任何对象都可以调用这些函数。
一 内置函数
1.1 apply 函数
apply
是 Kotlin
标准库中的一个函数,它允许您在调用对象的上下文中执行一系列操作,并返回该对象本身。这在构建对象的过程中非常有用,因为它允许您在对象创建和初始化的同时进行一些链式操作。
apply
函数的签名如下:
inline fun <T> T.apply(block: T.() -> Unit): T
这里的 T
是接收者对象的类型。block
参数是一个函数字面值,它可以在接收者对象上执行一系列操作。在函数字面值内部,可以通过 this
来访问接收者对象。
下面是一个使用 apply
函数的示例,假设我们要创建一个 Person
类的对象并初始化其属性:
package Expetion/*** @description:重点理解:apply函数的返回值是调用对象本身,也就是this* @author: shu* @createDate: 2023/8/8 19:50* @version: 1.0*/
// 定义一个数据类
data class Person(var name: String = "", var age: Int = 0)
fun main(){val person = Person("张三", 20)// apply函数的返回值是调用对象本身val result = person.apply {name = "李四"age = 30}println(result)println(person)
}
在这个例子中,我们通过 apply
函数在对象初始化的过程中设置了 name
和 age
属性,然后将初始化后的对象赋值给 person
变量。
apply
函数的一个主要优势是它允许您在初始化对象的同时进行链式操作,而无需显式地创建中间变量。这在代码的可读性和简洁性方面非常有帮助。
1.2 let 函数
let
是·Kotlin
标准库中的另一个函数,它也用于对对象执行一系列操作,但与 apply
不同,它在操作完成后返回一个可能不同的值。let
函数的主要用途是在一个非空的对象上执行操作,同时避免空引用异常。
let
函数的签名如下:
inline fun <T, R> T.let(block: (T) -> R): R
在这里,T
是接收者对象的类型,R
是 block
函数的返回类型。block
参数是一个函数字面值,它接受一个参数并返回一个值。
下面是一个使用 let
函数的示例,假设我们要对一个非空字符串执行一些操作:
package Expetion/*** @description: 重点理解:let函数的返回值是函数里面最后一行的返回值,也就是最后一行的返回值是什么,let函数的返回值就是什么* @author: shu* @createDate: 2023/8/8 19:55* @version: 1.0*/
// 定义一个数据类
data class Person01(var name: String = "", var age: Int = 0)
// let函数的返回值是函数里面最后一行的返回值
fun main(){val person = Person01("张三", 20)val result = person.let {it.name = "李四"it.age = 30"返回值"}println(result)println(person)
}
在这个例子中,我们使用了安全调用操作符 ?.
来调用 let
函数,以确保在 input
为非空的情况下才会执行 let
函数内部的操作。it
表示 input
的值,然后我们在 let
函数内部获取了字符串的长度,并将结果赋值给 result
变量。
let
函数在处理可空对象时特别有用,因为它允许您在对象非空的情况下执行一些操作,并获取一个非空的返回值。这有助于避免空引用异常并提高代码的安全性。
1.3 run函数
run
是 Kotlin 标准库中的另一个函数,它与 apply
和 let
有一些相似之处,但在使用上略有不同。run
函数允许您在对象上执行一系列操作,并返回最后一个操作的结果。与 let
不同,run
函数不仅可以在非空对象上使用,还可以在任何对象上使用。
run
函数的签名如下:
inline fun <T, R> T.run(block: T.() -> R): R
在这里,T
是接收者对象的类型,R
是 block
函数的返回类型。block
参数是一个函数字面值,它接受一个接收者对象并返回一个值。
下面是一个使用 run
函数的示例,假设我们要创建一个 Person
类的对象并执行一些操作:
package Expetion/*** @description:* @author: shu* @createDate: 2023/8/8 19:58* @version: 1.0*/
// 定义一个数据类
data class Person02(var name: String = "", var age: Int = 0)
//
fun main(){val person = Person02("张三", 20)val result = person.run {name = "李四"age = 30"返回值"}println(result)println(person)
}
在这个例子中,我们使用 run
函数在对象创建和初始化的过程中对 name
和 age
属性进行赋值,然后返回一个包含人物信息的字符串。
与 let
不同,run
函数不仅可以用于非空对象,还可以用于任何对象。它对于需要在一系列操作中执行某些操作并返回结果的情况非常有用。
使用场景区别
虽然 apply
、let
和 run
函数在某些方面相似,它们在使用场景和功能上有一些区别,让我们来总结一下这些区别:
-
返回值:
apply
:始终返回接收者对象本身。let
:返回函数字面值的结果,通常是对接收者对象的处理结果。run
:返回函数字面值的结果,通常是对接收者对象的处理结果。
-
使用场景:
apply
:适用于在对象初始化的过程中执行一系列链式操作,通常用于修改对象的属性。let
:适用于在非空对象上执行操作,可以用于执行任何类型的处理。run
:适用于执行一系列操作并返回最终结果,可以用于任何类型的对象。
-
对象引用:
apply
:在函数字面值内部可以使用this
引用接收者对象。let
:在函数字面值内部可以使用it
引用接收者对象。run
:在函数字面值内部可以使用this
引用接收者对象。
-
空安全:
apply
:通常用于非空对象,但也可以用于可空对象。let
:主要用于非空对象上,避免空引用异常。run
:可以在任何对象上使用,无论是否为空。
-
链式操作:
apply
:适用于在对象构建和初始化的同时进行一系列链式操作。let
:适用于在一系列操作中进行单独的处理。run
:适用于执行一系列操作并返回结果,但较适合复杂操作。
1.4 with函数
with
是 Kotlin
标准库中的另一个函数,它与之前提到的 apply
、let
和 run
有一些相似之处,但在使用方式和语义上略有不同。with
函数允许您在一个特定的对象上执行一系列操作,但不需要使用函数字面值,而是直接在一个代码块内操作对象。
with
函数的签名如下:
inline fun <T, R> with(receiver: T, block: T.() -> R): R
在这里,receiver
参数是接收者对象,T
是接收者对象的类型,R
是 block
函数的返回类型。block
参数是一个函数字面值,它接受一个接收者对象并返回一个值。
下面是一个使用 with
函数的示例,假设我们有一个 Rectangle
类,我们希望计算其面积和周长:
package Expetion/*** @description:* @author: shu* @createDate: 2023/8/8 20:03* @version: 1.0*/
class Rectangle(val width: Int, val height: Int)fun main() {val rectangle = Rectangle(10, 5)val areaAndPerimeter = with(rectangle) {val area = width * heightval perimeter = 2 * (width + height)"Area: $area, Perimeter: $perimeter"}println(areaAndPerimeter)
}
在这个例子中,我们使用 with
函数在 rectangle
对象上执行一系列操作,计算了面积和周长,并将结果字符串赋值给 areaAndPerimeter
变量。
与之前提到的函数不同,with
函数更注重于在特定对象上执行一系列操作,并且不需要在函数内部使用额外的 it
或 this
来引用接收者对象。
1.5 also函数
also
是 Kotlin
标准库中的另一个函数,类似于之前提到的 apply
、let
、run
和 with
函数,它也用于在对象上执行一系列操作,但在使用方式和返回值方面有一些不同。also
函数允许您在一系列操作中对对象进行修改,并返回该对象本身。
also
函数的签名如下:
inline fun <T> T.also(block: (T) -> Unit): T
在这里,T
是接收者对象的类型,block
参数是一个函数字面值,它接受一个接收者对象并不返回任何值,用于执行一系列操作。
下面是一个使用 also
函数的示例,假设我们要对一个列表进行操作并输出其中的元素:
package Expetion/*** @description:* @author: shu* @createDate: 2023/8/8 20:03* @version: 1.0*/fun main() {val numbers = mutableListOf(1, 2, 3, 4, 5)numbers.also {it.add(6)it.remove(2)}.forEach {println(it)}
}
在这个例子中,我们使用 also
函数对 numbers
列表进行了添加和删除操作,然后在链式调用中调用了 forEach
函数来输出列表中的元素。
also
函数适用于那些需要在一系列操作中修改对象本身,同时返回该对象的情况。与 apply
不同,also
的主要重点是执行操作,而不是在初始化过程中进行操作。
1.6 takeIf函数
在Kotlin
中,takeIf
是一个标准库函数,用于在特定条件下接收并返回对象。如果传递给 takeIf
函数的条件为真,则函数返回接收者对象,否则返回 null
。
takeIf
函数的签名如下:
inline fun <T> T.takeIf(predicate: (T) -> Boolean): T?
在这里,T
是接收者对象的类型,predicate
参数是一个函数字面值,它接受一个接收者对象并返回一个布尔值,用于判断是否应该接受该对象。
下面是一个使用 takeIf
函数的示例,假设我们要从一个字符串列表中找到第一个长度大于等于 5 的字符串:
package Expetion/*** @description:* @author: shu* @createDate: 2023/8/8 20:03* @version: 1.0*/fun main() {val strings = listOf("apple", "banana", "cherry", "date", "elderberry")val result = strings.firstOrNull { it.length >= 5 }?.takeIf { it.startsWith("e") }println(result)
}
在这个例子中,我们首先使用 firstOrNull
函数找到第一个满足长度大于等于 5 的字符串,然后我们通过链式调用使用 takeIf
函数来验证是否以字母 “e” 开头,如果是,则返回该字符串,否则返回 null
。
takeIf
函数适用于那些需要基于特定条件来选择对象的情况。
1.7 takeUnless函数
在 Kotlin 中,takeUnless
是一个标准库函数,与之前提到的 takeIf
函数类似,它也用于在特定条件下接收并返回对象。与 takeIf
不同的是,takeUnless
在条件为假时返回接收者对象,而在条件为真时返回 null
。
takeUnless
函数的签名如下:
inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T?
在这里,T
是接收者对象的类型,predicate
参数是一个函数字面值,它接受一个接收者对象并返回一个布尔值,用于判断是否应该拒绝该对象。
下面是一个使用 takeUnless
函数的示例,假设我们要从一个整数列表中找到第一个小于 5 的整数:
package Expetion/*** @description:* @author: shu* @createDate: 2023/8/8 20:03* @version: 1.0*/
fun main() {val numbers = listOf(3, 8, 1, 6, 4)val result = numbers.firstOrNull { it < 5 }?.takeUnless { it == 1 }println(result)
}
在这个例子中,我们使用 firstOrNull
函数找到第一个满足小于 5 的整数,然后通过链式调用使用 takeUnless
函数来验证是否等于 1,如果是,则返回 null
,否则返回该整数。
takeUnless
函数适用于需要基于特定条件来排除对象的情况。与 takeIf
函数相比,takeUnless
的返回逻辑相反,因此您可以根据情况选择使用哪个函数。
1.8 总结
让我们对之前提到的几个函数进行总结,以便更清楚地了解它们之间的区别:
-
apply:
- 返回接收者对象本身。
- 用于在对象初始化过程中执行一系列链式操作。
- 在函数字面值内部使用
this
引用接收者对象。 - 适用于对象的构建和初始化,通常用于修改属性。
-
let:
- 返回函数字面值的结果。
- 用于在非空对象上执行操作,避免空引用异常。
- 在函数字面值内部使用
it
引用接收者对象。 - 适用于在一系列操作中执行单独的处理,获取处理结果。
-
run:
- 返回函数字面值的结果。
- 可以在任何对象上使用。
- 在函数字面值内部使用
this
引用接收者对象。 - 适用于执行一系列操作并返回结果,较适合复杂操作。
-
with:
- 返回函数字面值的结果。
- 用于在特定对象上执行一系列操作。
- 在函数字面值内部直接操作对象,无需使用
it
或this
引用。 - 适用于在特定对象上执行多个操作,不关注初始化过程。
-
also:
- 返回接收者对象本身。
- 用于在一系列操作中修改对象并返回其本身。
- 在函数字面值内部使用
it
引用接收者对象。 - 适用于需要执行多个操作并保持链式调用,重点在于执行操作。
-
takeIf:
- 返回接收者对象本身或
null
。 - 用于根据条件接收对象,条件为真则返回
null
。 - 在函数字面值内部使用
it
引用接收者对象。 - 适用于基于条件接收对象的情况。
- 返回接收者对象本身或
-
takeUnless:
- 返回接收者对象本身或
null
。 - 用于根据条件接收对象,条件为真则返回对象,否则返回
null
。 - 在函数字面值内部使用
it
引用接收者对象。 - 适用于基于条件排除对象的情况。
- 返回接收者对象本身或
相关文章:
Kotlin理解内置函数
目录 一 内置函数1.1 apply 函数1.2 let 函数1.3 run函数1.4 with函数1.5 also函数1.6 takeIf函数1.7 takeUnless函数1.8 总结 Kotlin内置函数包括:let、run、with、apply、also,这些函数都是在Any类中定义的扩展函数,所以任何对象都可以调用…...

手机app测试
一、安装、卸载、更新、运行 1.安装、卸载 应用是否可以正常安装(命令行安装;apk/ipa安装包安装)(有网,无网是否都正常)卸载过程中出现死机,断电,重启等意外的情况&…...
Centos部署Git
Centos部署Git 文章目录 Centos部署Git部署步骤初始化配置免登录 部署步骤 初始化 -- 安装git yum install git配置免登录 配置git下载代码时 每次都需要输入密码的事情 -- 生成 gitconfig 文件 git config --global credential.helper store -- 配置登录邮箱 git config …...
k8s 控制器
Kubernetes(K8S)是一种开源的容器编排平台,它可以自动化地管理容器化应用程序的部署、扩展和运行。K8S中的控制器是一种重要的组件,它可以确保应用程序的状态与期望的状态一致。在K8S中,有五种常见的控制器,…...

谷歌关闭跨域限制.(生成一个开发浏览器),Chrome关闭跨域
(一)、首先找到浏览器在电脑磁盘中的位置,并复制 (二)、复制一个浏览器的快捷方式到桌面(不影响正常浏览器) (三)、chrom鼠标右键属性,修改快捷方式的目标 (四)chrome.exe 后面添加 --disable-web-security --user-data-dir 复制的Chrome浏览…...

实践指南-前端性能提升 270% | 京东云技术团队
一、背景 当我们疲于开发一个接一个的需求时,很容易忘记去关注网站的性能,到了某一个节点,猛地发现,随着越来越多代码的堆积,网站变得越来越慢。 本文就是从这样的一个背景出发,着手优化网站的前端性能&a…...

8月11日上课内容 nginx的多实例和动静分离
多实例部署 在一台服务器上有多个tomcat的服务。 配置多实例之前,看单个实例是否访问正常。 1.安装好 jdk 2.安装 tomcat cd /opt tar zxvf apache-tomcat-9.0.16.tar.gz mkdir /usr/local/tomcat mv apache-tomcat-9.0.16 /usr/local/tomcat/tomcat1 cp -a /usr…...

腾讯云CVM服务器端口在安全组中打开!
腾讯云服务器CVM端口怎么开通?腾讯云服务器端口是通过配置安全组规则来开通的,腾讯云服务器网以开通80端口为例来详细说下腾讯云轻量应用服务器开启端口的方法,其他的端口的开通如8080、1433、443、3306、8888等端口也适用于此方法࿰…...
k8s、docker添加daemon.json添加“exec-opts“: [“native.cgroupdriver=systemd“]后无法启动的问题
考虑k8s下docker下载镜像太慢,修改了daemon.json,按照手册抄,添加 {"exec-opts": ["native.cgroupdriversystemd"],"registry-mirrors": ["https://kn0t2bca.mirror.aliyuncs.com"] }结果发现k8s起…...
React组件性能优化实践
React组件性能优化最佳实践 React组件性能优化的核心是减少渲染真实DOM节点的频率,减少 Virtual DOM比对的频率。 组件卸载前进行清理操作 在组件中为 window注册的全局事件,以及定时器,在组件卸载前要清理掉,防止组件卸载后继…...

SpringBoot复习:(29)静态资源的配置路径
WebMvcAutoConfiguration 首页处理:...

mysql延时问题排查
背景介绍 最近遇到一个奇怪的问题,有个业务,每天早上七点半产生主从延时,延时时间12.6K; 期间没有抽数/备份等任务;查看慢日志发现,期间有一个delete任务,在主库执行了161s delete from xxxx_…...
接口设置了responseType:‘blob‘后,接收不到后端错误信息
下载文件流,需要接口设置responseType:blob,接口设置了responseType:blob后,拿不到后端接口的异常信息,我们只需要添加如下代码: const service axios.create({baseURL: ***, // url base url request url// withC…...

无涯教程-Perl - mkdir函数
描述 此功能使用MODE指定的模式创建一个名称和路径EXPR的目录,为清楚起见,应将其作为八进制值提供。 语法 以下是此函数的简单语法- mkdir EXPR,MODE返回值 如果失败,此函数返回0,如果成功,则返回1。 例 以下是显示其基本用法的示例代码- #!/usr/bin/perl -w$dirname &…...

css3 瀑布流布局遇见截断下一列展示后半截现象
css3 瀑布流布局遇见截断下一列展示后半截现象 注:css3实现瀑布流布局简直不要太香~~~~~ 场景-在uniapp项目中 当瀑布流布局column-grap:10px 相邻两列之间的间隙为10px,column-count:2,2列展…...

C++初阶之一篇文章教会你list(理解和使用)
list(理解和使用) 什么是list特点和优势基本操作示例用法与其他序列式容器(如 std::vector 和 std::deque)相比,std::list 显著的区别和优势成员类型 list构造函数1. default (1)2. fill (2)3.range (3)4. copy (4) li…...

如何给Linux开启swap虚拟内存
查看系统内存资源 free -h 创建swap分区 dd if/dev/zero of/swapfile bs1024 count4194304dev/zero:是Linux的一种特殊字符设备(输入设备),可以用来创建一个指定长度用于初始化的空文件,如临时交换文件,该设备无穷尽地提供0&…...

spring按条件注入@Condition及springboot对其的扩展
概述 spring的ioc极大的方便了日常开发,但随着业务的迭代。配置的一些参数在某些情况下需要按条件注入。 比如原先定义的db公共模块下,相关的配置和工具类只是基于mysql的。但是后续有模块需要使用mongo/es等其他数据库,又想继续使用db公共…...

MySQL多表连接查询3
目录 表结构 创建表 表数据 查询需求: 1.查询student表的所有记录 2.查询student表的第2条到4条记录 3.从student表查询所有学生的学号(id)、姓名(name)和院系(department)的信息 4.从s…...

【从零开始学习JAVA | 第四十五篇】反射
目录 前言: 反射: 使用反射的步骤: 1.获取阶段: 2.使用阶段: 反射的应用场景: 使用反射的优缺点: 总结: 前言: Java中的反射是一项强大而灵活的功能࿰…...

srs linux
下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935,SRS管理页面端口是8080,可…...

现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...

Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...

Golang——9、反射和文件操作
反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...

基于Java+VUE+MariaDB实现(Web)仿小米商城
仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意:运行前…...
云原生周刊:k0s 成为 CNCF 沙箱项目
开源项目推荐 HAMi HAMi(原名 k8s‑vGPU‑scheduler)是一款 CNCF Sandbox 级别的开源 K8s 中间件,通过虚拟化 GPU/NPU 等异构设备并支持内存、计算核心时间片隔离及共享调度,为容器提供统一接口,实现细粒度资源配额…...