前言
本篇文章接着上一篇文章全网最全面的由浅到深的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对象本身,否则返回null
return 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对象本身,否则返回null
return 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处理,并存入新的集合destination
destination.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)
}
//返回新的字符串StringBuilder
return 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~