全网最全面的由浅到深的Kotlin基础教程(七)

前言

本篇文章接着上一篇文章全网最全面的由浅到深的Kotlin基础教程(六)继续进阶学习kotlin,建议看完上一篇文章,再来看本篇文章。本篇主要分析一些常用的kotlin函数源码,以及用kotlin简单实现Rxjava的几个操作符。坚持将kotlin系列的前6篇看完的,那么恭喜你再将这最后一篇看完,你就成为一名合格的kotlin开发者了。

1. kotlin标准函数源码解析

1.1 apply

源码及分析注释如下:

/*
public 访问修饰符
inline fun 内联函数
<T> 泛型定义
T.apply 泛型T的扩展函数
(block: T.() -> Unit) 输入参数为一个名为block的lambda表达式,其中T.() 是一个泛型扩展函数,这种写法使得lambda表达式持有T的this对象,当做固定写法来理解即可。
: T apply函数的返回类型仍然为T
*/
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {//契约函数,暂时不用关注,可以不写的contract {callsInPlace(block, InvocationKind.EXACTLY_ONCE)}//执行lambda表达式的逻辑block()//最终仍然返回T对象本身return this
}

1.2 also

与apply函数的意义一样,只是also函数的lambda表达式持有it,而apply函数的的lambda表达式持有this,源码及分析注释如下:

/*
public 访问修饰符
inline fun 内联函数
<T> 泛型定义
T.also 为泛型T定义扩展函数also
block: (T) -> Unit also函数中传入的参数是lambda表达式,该lambda表达式有一个T泛型的参数,返回值为空
: T also函数的最终返回值仍然为T泛型
*/
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.also(block: (T) -> Unit): T {contract {callsInPlace(block, InvocationKind.EXACTLY_ONCE)}//执行lambda表达式,将T泛型的this对象传入block函数,因此block通过it持有T泛型的this对象block(this)//不管你上面的lambda表达式干了啥,最终仍然返回T泛型对象本身return this
}

1.3 run

源码及分析注释如下:

/*
public 访问修饰符
inline fun 内联函数
<T, R> 定义两个泛型
T.run 为T泛型定义扩展函数run
block: T.() -> R run函数有一个参数是lambda表达式,该lambda表达式通过T泛型扩展函数,拥有T泛型的this对象,返回类型为R
: R run函数的返回类型是R泛型
*/
@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {contract {callsInPlace(block, InvocationKind.EXACTLY_ONCE)}//执行lambda表达式//因为lambda表达式拥有T泛型的this对象//因为lambda表达式返回的是R,因此返回值由lambda表达式的最后一行决定//return this.block()  //this可以省略return block()
}

1.4 let

与run函数的意义一样,只是let函数的lambda表达式持有it,而run函数的的lambda表达式持有this,源码及分析注释如下:

/*
public 访问修饰符
inline fun 内联函数
<T, R> 定义两个泛型
T.let 为T泛型定义扩展函数let
block: (T) -> R lambda表达式参数,输入T泛型(lambda表达式如果只有一个参数,则参数名默认为it),输出为R泛型
: R 最终返回的类型是R泛型
*/
@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {contract {callsInPlace(block, InvocationKind.EXACTLY_ONCE)}//执行lambda表达式//因为lambda表达式传入的是this,因此lambda表达式通过it持有T泛型的对象//因为lambda表达式输入的T,返回的是R,因此返回值由lambda表达式的最后一行决定return block(this)
}

1.5 with

与run函数的意义一样,只是调用方式不一样而已,run是泛型扩展函数,而with是普通的函数,源码及分析注释如下:

/*
public 访问修饰符
inline fun 内联函数
<T, R> 定义两个泛型
with(receiver: T, block: T.() -> R) 这是一个普通的函数,并非扩展函数,包括两个参数,第一个T泛型的参数,第二个是lambda表达式,lambda表达式通过T泛型扩展函数,拥有T泛型的this对象,返回类型为R
: R 最终返回类型是R
*/
@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {contract {callsInPlace(block, InvocationKind.EXACTLY_ONCE)}//block的最后一行是返回值return receiver.block()
}

1.6 takeIf

源码及分析注释如下:

/*
public 访问修饰符
inline fun 内联函数
<T> 泛型定义
T.takeIf 为泛型T定义扩展函数takeIf
predicate: (T) -> Boolean takeIf函数中传入的参数是lambda表达式,该lambda表达式有一个T泛型的参数,返回值为Boolean
: T? takeIf函数最终返回的可空的T泛型类型
*/
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? {contract {callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)}//如果lambda表达式返回true,则takeIf返回T泛型this对象本身,否则返回nullreturn if (predicate(this)) this else null
}

1.7 takeUnless

与takeIf的意义相反,源码及分析注释如下:

/*
public 访问修饰符
inline fun 内联函数
<T> 泛型定义
T.takeUnless 为泛型T定义扩展函数takeUnless
predicate: (T) -> Boolean takeUnless函数中传入的参数是lambda表达式,该lambda表达式有一个T泛型的参数,返回值为Boolean
: T? takeIf函数最终返回的可空的T泛型类型
*/
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? {contract {callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)}//如果lambda表达式返回false,则takeUnless返回T泛型this对象本身,否则返回nullreturn if (!predicate(this)) this else null
}

2. kotlin转换函数源码解析

2.1 map

  • 功能介绍:
    源码及分析注释如下:把lambda表达式的返回结果(最后一行),添加到新的集合destination中,并返回。
  • 示例代码:
fun main() {var list = listOf("A", "B", "C")list.map {"[$it]"}.map {"[$it, len=${it.length}]"}.map {print("$it ")}}

运行结果如下:
在这里插入图片描述

  • 源码分析:
//Iterable类的扩展函数map
public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {//将创建的List数组和lambda表达式传入mapTo函数//return this.mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform) //this可以省略return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.mapTo(destination: C, transform: (T) -> R): C {//遍历调用map的List对象for (item in this)//将原有的list值传递给lambda表达式transform处理,并存入新的集合destinationdestination.add(transform(item))return destination //返回新的集合
}

2.2 flatmap

  • 功能介绍:
    lambda表达式的返回结果是一个集合,把lambda表达式的返回集合,通过addAll函数铺开,并添加到新的集合destination中,最后返回新的集合。
  • 示例代码:
fun main() {var list = listOf("A", "B", "C")list.flatMap {listOf("[$it ,", "$it]")}.map {print("$it ")}
}

运行结果如下:
在这里插入图片描述

  • 源码分析:
//Iterable类的扩展函数
public inline fun <T, R> Iterable<T>.flatMap(transform: (T) -> Iterable<R>): List<R> {return flatMapTo(ArrayList<R>(), transform)
}public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.flatMapTo(destination: C, transform: (T) -> Iterable<R>): C {//遍历flatMap调用者的集合元素for (element in this) {//lambda表达式返回一个集合val list = transform(element)//将lambda表达式返回的集合添加到新的集合destination中destination.addAll(list)}//返回新的集合return destination
}

2.3 filter

  • 功能介绍:
    如果lambda表达式的返回值为true,则遍历当前元素,加入新的字符串构造器StringBuilder destination,否则,不加入新的字符串。最后返回新的字符串
  • 示例代码:
fun main() {var list = listOf("A", "B", "C")list.map {//过滤list中为A的元素it.filter { it ->println("$it filter")it == 'A'}}.map {print("$it  ")}
}

运行结果如下:
在这里插入图片描述

  • 源码分析:
//String类的扩展函数filter
public inline fun String.filter(predicate: (Char) -> Boolean): String {return filterTo(StringBuilder(), predicate).toString()
}public inline fun <C : Appendable> CharSequence.filterTo(destination: C, predicate: (Char) -> Boolean): C {//遍历filter调用者的字符串的所有字符for (index in 0 until length) {val element = get(index)//如果这个字符传入lambda表达式predicate的返回结果为true,则添加到StringBuilder中if (predicate(element)) destination.append(element)}//返回新的字符串StringBuilderreturn destination 
}

2.4 zip

  • 功能介绍
    通过lambda表达式将第一个集合和另一个集合,以Pair的形式添加到新的集合中,并返回
  • 示例代码
fun main() {val name = listOf("sun", "mekeater")val age = listOf(18,19)var zip = name.zip(age)//将zip转为Map遍历zip.toMap().forEach{println("name=${it.key},age=${it.value}")}
}

运行结果如下:
在这里插入图片描述

  • 源码分析
//Iterable类的扩展函数zip
public infix fun <T, R> Iterable<T>.zip(other: Iterable<R>): List<Pair<T, R>> {return zip(other) { t1, t2 -> t1 to t2 }
}
//中缀表达式,将A和B组合成一个Pair对象
public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)public inline fun <T, R, V> Iterable<T>.zip(other: Iterable<R>, transform: (a: T, b: R) -> V): List<V> {//zip函数调用者对象遍历器val first = iterator()//zip函数中传入的另一个集合对象遍历器val second = other.iterator()//新建集合val list = ArrayList<V>(minOf(collectionSizeOrDefault(10), other.collectionSizeOrDefault(10)))//遍历两个集合while (first.hasNext() && second.hasNext()) {//将两个集合的元素传给lambda表达式transform//上面可以看到transform的实现,是将两个参数组合为一个Pair//将Pair对象添加到新的集合list中list.add(transform(first.next(), second.next()))}//返回新的集合return list
}

3. 函数式编程理解

kotlin是函数式编程语言,函数式编程语言的代码更简洁直观(如果你会的话,真的很容易读懂,但如果不会,那真的又一一点看不懂,相信认真看了我kotlin这7篇文章的,到这儿应该都能轻松的读懂下的kotlin代码),我们以一段示例代码来对比下,函数式编程和普通编程方式的区别。

如下一段kotlin函数式编程,用普通的java代码写,需要写一堆才能实现

fun main() {val name = listOf("sun", "mekeater")val age = listOf(18,19)//name.zip(age) 将name和age两个集合组成键值对集合//.toMap() 将上一步键值对集合转为Map集合//.map { "name:${it.key},age:${it.value}"} 遍历上一步Map集合中的元素,按照"name:${it.key},age:${it.value}"格式进行组合//.map { println(it) 遍历上一步Map集合中的元素,进行打印输出name.zip(age).toMap().map { "name:${it.key},age:${it.value}"}.map { println(it) }
}

对上面的kotlin函数式编程写的代码用java实现,示例代码如下:

public class Kt43_java {public static void main(String[] args) {List<String> names=new ArrayList<>();names.add("sun");names.add("mekeater");List<Integer> ages =new ArrayList<>();ages.add(18);ages.add(19);Map<String, Integer> map =new LinkedHashMap<>();for (int i = 0; i < names.size(); i++) {map.put(names.get(i), ages.get(i));}List<String> newList=new ArrayList<>();for (Map.Entry<String, Integer> stringIntegerEntry : map.entrySet()) {newList.add("name:"+stringIntegerEntry.getKey()+" age:"+stringIntegerEntry.getValue());}for (String s : newList) {System.out.println(s);}}}

kotlin的一行代码,java要用一堆才能实现,kotlin代码的简洁程度不言而喻!

4. 手写RxJava

采用kotlin代码实现RxJava的create,map,observer三个操作符,通过这个示例,真的更能感受到kotlin代码的简洁程度令人发指,哈哈哈

fun main() {create {"mekeater"}.map {"[$this]"}.map {"==$this=="}.observer {println(this)}
}
class RxjavaCoreClass<T>(val item:T)//lambda对输入进行处理
inline fun<I> RxjavaCoreClass<I>.observer(observerAction:I.()->Unit):Unit = observerAction(item)//对于输入进行处理,转换为输出给到RxjavaCoreClass
inline fun<I,O> RxjavaCoreClass<I>.map(mapAction:I.()->O) = RxjavaCoreClass(mapAction(item))//create操作符只是将用户最后一行的输入原样输出给RxjavaCoreClass,起到一个输入参数的作用
inline fun<O> create(action:()->O) = RxjavaCoreClass(action())

运行结果如下:
在这里插入图片描述

5. 结语

自此,我们kotlin入门教程系列就讲完了,一共7篇文章,如果您能从第一篇看到第七篇,相信你已经很好的掌握kotlin语言了,至少能够看懂kotlin代码,能够自己上手写kotlin代码了。

那么,感谢你来我的博客世界,听我讲kotlin的故事,这个故事该说再见了,希望在下个新故事,还能遇到你,886~

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

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

相关文章

全志A133 android10 调试vibrator震动马达

一&#xff0c;前提条件 全志使用的马达配置为上电震动&#xff0c;下电停止&#xff0c;需测试硬件是否正常。马达供电最好为独立供电&#xff0c;避免干扰。 二&#xff0c;适配步骤 1. dts中增加马达配置 motor_para {compatible "allwinner,sunxi-vibrator";…

BGP实验:联邦和发射器实验

BGP实验&#xff1a;联邦和发射器实验 一、实验拓扑 二、实验要求及分析 实验要求&#xff1a; 1、AS1存在两个环回&#xff0c;一个地址为192.168.1.0/24&#xff0c;该地址不能再任何协议中宣告&#xff1b; ​ AS3存在两个环回&#xff0c;一个地址为192.168.2.0/24&…

解决ModuleNotFoundError: No module named ‘open_clip‘问题

在使用stable diffusion大模型时&#xff0c;添加一些模型后启动df页面报错&#xff1a;ModuleNotFoundError: No module named open_clip 使用 pip install open_clip命令下载失败&#xff0c;报错&#xff1a; Looking in indexes: https://mirrors.aliyun.com/pypi/simple…

Redis【B站面试题】

前言 2023-07-27 22:44:59 出自B站 灰灰的Java面试 Redis Redis为什么快&#xff1f; 1.纯内存KV操作 Redis的操作都是基于内存的&#xff0c;CPU不是 Redis性能瓶颈,&#xff0c;Redis的瓶颈是机器内存和网络带宽。 在计算机的世界中&#xff0c;CPU的速度是远大于内存的速…

深度学习之基于TensorFlow人脸表情识别

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 人脸表情识别是计算机视觉领域的重要研究方向之一&#xff0c;它在人机交互、情感分析、安全监控等领…

Java 变量和作用域:理解变量的声明、初始化及其作用域

在Java编程语言中&#xff0c;变量和作用域是两个核心概念。理解变量的声明、初始化以及它们的作用域对于编写健壮且高效的代码至关重要。 变量的声明与初始化 变量的声明 在Java中&#xff0c;变量的声明指的是定义变量的名称和类型。在Java中&#xff0c;变量声明的一般语…

ubuntu使用记录——如何使用wireshark网络抓包工具进行检测速腾激光雷达的ip和端口号

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言wireshark网络抓包工具1.wireshark的安装2.wireshark的使用3.更改雷达ip 总结 前言 Wireshark是一款备受赞誉的开源网络协议分析软件&#xff0c;其功能之强大…

简述MyBatis中#{}引用和${}引用的区别

各位大佬光临寒舍&#xff0c;希望各位能赏脸给个三连&#xff0c;谢谢各位大佬了&#xff01;&#xff01;&#xff01; 目录 1.有无预编译 优点 缺点 2.SQL执行的快慢 3.能否被SQL注入 4.参数输入方式 5.总结 1.有无预编译 #{}是有预编译的而${}是没有预编译的&…

LiveGBS流媒体平台GB/T28181用户手册-服务器概览:通道信息、负载信息、CPU使用、存储使用、带宽使用(Mbps)、内存使用

LiveGBS用户手册-服务器概览&#xff1a;通道信息、负载信息、CPU使用、存储使用、带宽使用&#xff08;Mbps&#xff09;、内存使用 1、服务器概览1.1、通道信息1.2、负载信息1.2.1、信息说明1.2.2、会话列表 1.3、CPU使用1.4、存储使用1.5、带宽使用&#xff08;Mbps&#xf…

15:00面试,15:08出来,面试问的有点变态。。。。

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天…

阿里云数据库 SelectDB 版全面商业化,开启现代化实时数据仓库的全新篇章

2024 年 5 月 21 日&#xff0c;由阿里云联合飞轮科技共同举办的「阿里云数据库 SelectDB 版商业化产品发布会」于线上召开。阿里巴巴集团副总裁、阿里云数据库产品事业部负责人李飞飞宣布&#xff0c;阿里云数据库 SelectDB 版在中国站及国际站全面发布&#xff0c;正式开启商…

ROS | 用C++和python实现运动控制功能

基础知识&#xff1a; 用C实现&#xff1a; C代码&#xff1a; 用python实现&#xff1a; Python代码&#xff1a;

数据库理论基本概念

数据库理论基本概念 三级模式和两级映像 外模式 > 用户和数据库系统的接口 -------- 外模式-概念模式映射 概念模式 > 数据的逻辑结构和特征的描述 -------- 概念模式-内模式映射 内模式 > 数据物理结构和存储方式的描述三级…

避雷:搭建ai知识库的6大注意事项

随着人工智能技术的发展&#xff0c;ai知识库成为众多企业追求的一个重要部分&#xff0c;帮助企业提高运营次效率&#xff0c;越来越受到人们的关注。但是&#xff0c;在搭建ai知识库的过程中&#xff0c;稍不留意&#xff0c;就会漏掉一些小细节&#xff0c;导致做出来的ai知…

GPT-4o 引领人机交互新风向的向量数据库Milvus Cloud 成本

成本 AIGC 时代对于冷热储存的呼唤 成本一直是向量数据库获得更广泛使用的最大阻碍之一,这个成本来自两点: 储存,绝大多数向量数据库为了保证低延迟,需要把数据全量缓存到内存或者本地磁盘。在这个动辄百亿量级的AI 时代,意味着几十上百 TB 的资源消耗。 计算,数据需…

OpenFeign高级用法:缓存、QueryMap、MatrixVariable、CollectionFormat优雅地远程调用

码到三十五 &#xff1a; 个人主页 微服务架构中&#xff0c;服务之间的通信变得尤为关键。OpenFeign&#xff0c;一个声明式的Web服务客户端&#xff0c;使得REST API的调用变得更加简单和优雅。OpenFeign集成了Ribbon和Hystrix&#xff0c;具有负载均衡和容错的能力&#xff…

线性回归模型之套索回归

概述 本案例是基于之前的岭回归的案例的。之前案例的完整代码如下&#xff1a; import numpy as np import matplotlib.pyplot as plt from sklearn.linear_model import Ridge, LinearRegression from sklearn.datasets import make_regression from sklearn.model_selectio…

NegativePrompt:利用心理学通过负面情绪刺激增强大型语言模型

【摘要】大型语言模型 (LLM) 已成为各种应用不可或缺的一部分&#xff0c;从传统的计算任务到高级人工智能 (AI) 应用。这种广泛的应用促使社会科学等各个学科对 LLM 进行了广泛的研究。值得注意的是&#xff0c;研究表明 LLM 具有情商&#xff0c;可以通过积极的情绪刺激进一步…

C++:深入理解多态

一、多态的概念 多态的概念&#xff1a;通俗来说&#xff0c;就是多种形态&#xff0c;具体点就是去完成某个行为&#xff0c;当不同的对象去完成时会产生出不同的状态。 那究竟多态的实际价值体现在哪里呢&#xff1f;&#xff1f; 1、举个例子比如说购买高铁票这个行为&…