携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第11天,点击查看活动详情
本篇文章主要是介绍
buildString{}
、buildList{}
、buildSet{}
、buildMap{}
系列API的基本使用,通过了解希望可以给你日常开发带来遍历。
1.buildString{}
动态构建String
平常我们构造字符串为了避免通过+
的形式频繁创建中间String
对象,一般会使用StringBuild
来动态字符串:
fun test1() {
val build = StringBuilder()
build.append("a")
val tmp = "10".repeat(10)
build.append(tmp)
}
kotlin.text
包下提供了buildString{}
扩展,来更优雅的动态创建String
:
public inline fun buildString(builderAction: StringBuilder.() -> Unit): String {
contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
return StringBuilder().apply(builderAction).toString()
}
定义了一个接收者为StringBuild
的参数,所以我们就能在lambda中调用StringBuild
的public的方法实现插入。最终构建StringBuilder
对象并转成String返回。
使用如下:
fun test1() {
val content: String = buildString {
append("a")
append("b".repeat(10))
}
}
其中官方库还提供了一个重载方法:
buildString(capacity: Int, builderAction: StringBuilder.() -> Unit){}
可以指定StringBuild
初始容量。
下面介绍下官方为StringBuild
提供的有用的几个扩展方法“
1.1 append(vararg value: String?)
插入多值
fun test1() {
val content: String = buildString {
//一次性插入多值
append("a", "b".repeat(10), "b".repeat(10))
}
}
1.2 appendLine()
插入换行
public inline fun StringBuilder.appendLine(): StringBuilder = append('\n')
上面为源码实现。
1.3 appendLine(value: CharSequence?)
插入值后追加换行
public inline fun StringBuilder.appendLine(value: CharSequence?): StringBuilder = append(value).appendLine()
源码中,就是在插入换行之前先插入传递的参数。
1.4 set(index: Int, value: Char)
重载[]
插入指定位置字符
public expect operator fun StringBuilder.set(index: Int, value: Char)
使用如下:
val content: String = buildString {
//小心数组越界异常
this[5] = 'b'
}
2. buildList<T>{}
构造List
public inline fun <E> buildList(@BuilderInference builderAction: MutableList<E>.() -> Unit): List<E> {
contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
return buildListInternal(builderAction)
}
这个方法需要在kotlin1.6
及之上的版本稳定使用,使用如下:
val list = buildList<String> {
add("haha")
add("ddd")
}
同样官方库也提供了一个重载方法buildList(capacity: Int, @BuilderInference builderAction: MutableList<E>.() -> Unit)
可以指定集合初始化的容量。
下面介绍几个有用的集合扩展方法/属性:
2.1 Collection<*>.indices
获取集合索引集合
public val Collection<*>.indices: IntRange
get() = 0..size - 1
这个扩展属性在遍历集合的挺有用:
fun test2() {
val list = mutableListOf<String>()
for (i in list.indices) {
println(list[i])
}
}
2.2 isNullOrEmpty()
contract形式集合判空
public inline fun <T> Collection<T>?.isNullOrEmpty(): Boolean {
contract {
returns(false) implies (this@isNullOrEmpty != null)
}
return this == null || this.isEmpty()
}
这个扩展关键的是contract
关键子,当isNullOrEmpty()
返回false的时候让我们在if表达式中直接通过list.xxx()
操作集合成员,而不需要带list?.xxx()
这样操作。
最近看了掘金一篇介绍
contract
文章,推荐给大家:Kotlin 标准库随处可见的 contract 到底是什么?。
2.3 orEmpty()
接受者为空默认创建空集合
public inline fun <T> List<T>?.orEmpty(): List<T> = this ?: emptyList()
源码很简单,大家平常也会经常使用?:
判断集合为空时,返回一个默认空集合,这里都给大家封装好了,安心食用。
2.4 shuffled(random: Random)
打乱集合元素顺序
public fun <T> Iterable<T>.shuffled(random: Random): List<T> = toMutableList().apply { shuffle(random) }
public fun <T> MutableList<T>.shuffle(random: Random): Unit {
for (i in lastIndex downTo 1) {
val j = random.nextInt(i + 1)
this[j] = this.set(i, this[j])
}
}
核心实现就是这个shuffle()
方法,通过random.nextInt
随机下标,和索引下标对应的元素互相交换,最终实现洗牌操作
。
3. buildSet{}
、buildMap{}
set构建如下:
val set = buildSet<String> {
add("20")
}
map构建如下:
val map = buildMap<String, String> {
this["a"] = "b"
}
一个构造set集合,一个构造哈希表,使用和上面的buildList{}
差不多,具体的使用就不再多做描述了,请注意也要在kotlin1.6
及以上版本才能稳定使用。
历史文章
之前也写过官方库给我提供的遍历的扩展API,大家感兴趣的可以看下: