五、kotlin标准库函数


theme: channing-cyan

标准库函数

我按照返回值做了区分, 这样好理解, 如果标准函数返回的自己, 则我们可以做属于自己的的链式调用, 如果返回的是别人, 可以做别人的链式调用, 如果函数类型参数有扩展, 则可以使用this

返回新的值

let 函数

let函数把this当作参数传递给lambda的参数, 然后返回lambda的返回值

val first = listOf(1, 2, 3).first()
val res = first * first
println(res)

println(listOf(1, 2, 3).first().let { it * it })
public inline fun <T, R> T.let(block: (T) -> R): R {
    return block(this)
}

返回新的值(函数类型参数带扩展)

with 函数(不是扩展函数)

val with = fun MutableList<Int>.(): Int {
	this[0] += 1
	return this[0]
}

fun main() {
	val list = with(listOf(1, 2, 3)) {
		this.map {
			it + 1
		}
	}
	println(list)
	println(mutableListOf(1, 2, 3).with())
//	with(listOf(1, 2, 3))
}

with 函数第一个参数是传递接收者, 第二个参数传递的是 匿名扩展函数类型

image.png

上面的代码我写了个匿名扩展函数变量, 可以代替 with 函数, 而且使用方式很像

kotlin源码:

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

block: T.() -> R的使用方法有两种, 第一种是 block(this) 这种方式调用, 还有一种就是 this.block() 的方式调用, 这两种都行, 第一种是我们跳过编译器主动传递 this 进去, 第二种是 编译器主动将接收者当作 参数 传递进去

with的使用场景
const val letter: String = "abcdefghijklmnopqrstuvwxyz"

fun alphabet01(): String {
    val stringBuilder = StringBuilder()
    letter.forEach { stringBuilder.append(it.uppercaseChar()) }
    stringBuilder.append("\nNow I know the alphabet!")
    return stringBuilder.toString()
}

使用 stringBuilder 对象本身数量有点多的时候, 可以考虑使用 with

fun alphabet02() = kotlin.with(StringBuilder()) {
    letter.forEach { if (it in 'a'..'z') {
//        append(it.minus('a').plus('A'.code).toChar())
        append(it.uppercaseChar())
    } }
    append("\nNow I know the alphabet!")
    toString()
}

我们还可以使用 buildString, 它底层使用的还是 StringBuilder 所以这样可以这样:

fun alphabet03() = buildString {
    for (c in letter) {
        append(c.uppercaseChar())
    }
    append("\n" +
            "Now I know the alphabet!")
}

它在返回的时候, 返回的是 String 类型

StringBuilder().apply(builderAction).toString()

run 扩展函数

val s = File("""D:\test.txt""").run {
    if (canRead()) reader().buffered().use { it.readText() } else null
}
println(s)
public inline fun <T, R> T.run(block: T.() -> R): R {
    return block()
}

use 扩展函数

主要用于文件流操作, 帮助添加 try catch finally

val s = FileReader("""D:\test.txt""").buffered().use {
    it.readText()
}
println(s)

image.png

返回自己

also 扩展函数

also 支持链式调用

使用方法:

val file = File("""D:\test.txt""").also {
    println(it.name)
}.also {
    // println(it.readLines())
    println(it.readText())
}

kotlin also 底层函数:

public inline fun <T> T.also(block: (T) -> Unit): T {
    block(this)
    return this
}

taskIf 扩展函数

如果满足 taskIf 的条件(为 true), 则返回 this , 否则 返回 null

val file = File("""D:\test.txt""").takeIf {
    it.canRead() && it.canWrite()
}
println(file)
public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? {
    return if (predicate(this)) this else null
}

很简单, 函数参数 predicate , 使用 predicate 函数 , 传递 this 进入函数体中执行, 然后返回 boolean, 同 Boolean 判断 如果 为 true 则返回 this , 否则返回 false

这个也可以链式调用, 但是需要判断是否 可空 比较麻烦一点

taskUnless 扩展函数

如果表达式不满足条件, 则返回 this, 否则返回 null

val file = File("""D:\test.txt""").takeUnless {
    it.isDirectory
}
println(file)
public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? {
    return if (!predicate(this)) this else null
}

注意上面 takeIftakeUnless 都返回的可空类型, T?

withLock 线程锁扩展函数

val l: Lock = ReentrantLock()
l.withLock {
   // ...........
}
public inline fun <T> Lock.withLock(action: () -> T): T {
    lock()
    try {
        return action()
    } finally {
        unlock()
    }
}

返回自己(函数类型参数带扩展)

apply 函数

用法:

val file1 = File("""D:\test.txt""")
file1.setWritable(true)
file1.setReadable(true)
file1.setExecutable(true)

val file2 = File("""D:\test.txt""").apply {
    setWritable(true)
    setReadable(true)
    setExecutable(true)
}

应用场景:

apply 类似于一个配置函数, 用于配置接收者, 然后再返回配置好的接收者

解析:

public inline fun <T> T.apply(block: T.() -> Unit): T {
    block()
    return this
}

把接收者作为 T 带入 File.apply(block: File.() -> Unit): File , 我们解析一下:

  1. 他是 File 的扩展函数
  2. 他返回 File 对象本身
  3. 他传递一个 匿名扩展函数(带 this 参数的 lambda 表达式函数), 函数返回值为 Unit

这里需要注意一点, block 是 lambda 表达式, 把 lambda 表达式传递进另一个函数体内部, lambda就可以访问表达式外部函数体作用域能访问的所有东西, 这是闭包

闭包就是能够读取其他函数内部变量的函数, 或者叫 定义在一个函数内部的函数, 这样函数体内部能够访问函数体外部的, 本质上,闭包是将函数内部和函数外部连接起来的桥梁

在 idea 查找扩展函数的方法

安装 extSee 插件

然后就能看到了

image.png

image.png

使用 idea 的 find usages

不推荐, 这种方式查询出来的东西太多了, 不能够限定只查询 extension

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TIpa5UMp-1656299586587)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/233ee3a7759c4082b202ab0118822dc9~tplv-k3u1fbpfcp-watermark.image?)]

将函数内部和函数外部连接起来的桥梁

在 idea 查找扩展函数的方法

安装 extSee 插件

然后就能看到了

[外链图片转存中…(img-n0PcYruw-1656299586585)]

[外链图片转存中…(img-DuPnalZq-1656299586586)]

使用 idea 的 find usages

不推荐, 这种方式查询出来的东西太多了, 不能够限定只查询 extension

[外链图片转存中…(img-TIpa5UMp-1656299586587)]

image.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值