Kotlin中的特殊函数简介

Android  Kotlin  2024年8月30日 pm4:48发布2个月前更新 91es.com站长
130 0 0

前言

简单记录一下Kotlin中的run()、apply()、let()、also()和with()等特殊的函数,方便自己查阅。

正文

run()

@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}

作用:执行一个代码块并返回其结果。

run()在内部运行对象是通过this访问的,当您想要调用对象的方法而不是将其作为参数传递时,这是很有用的。

使用场景

适用于let,with函数任何场景。

因为run函数是let,with两个函数结合体,准确来说它弥补了let函数在函数体内必须使用it参数替代对象,在run函数中可以像with函数一样可以省略,直接访问实例的公有属性和方法,另一方面它弥补了with函数传入对象判空问题,在run函数中可以像let函数一样做判空处理。

简单使用
//使用1
val website: String = "91es.com";
var name = website.run {
    Log.d(TAG, "run : " + isEmpty())
    Log.d(TAG, "run : $length");
    this
};
Log.d(TAG, "name : $name")

//使用2
private fun test(): String {
    return Thread.currentThread().name;
}
var test = run { test() }
Log.d(TAG, "test : $test")

执行后结果

run : false
run : 8
name : 91es.com

test : main

得出如下结果:

  1. run()内部可通过this获取调用对象,并调用其方法。

  2. run()返回值为最后一行的值或者指定的return的表达式。

  3. run()执行在主线程中。

apply()

@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}

对比run(),apply()不同的是,先是调用了block()函数,然后返回当前的调用者对象this。

apply在对象上执行代码块并返回对象本身。在块内部,对象被this引用。这个函数对于初始化对象很方便。

使用场景

整体作用功能和run函数很像,唯一不同点就是它返回的值是对象本身,而run函数是一个闭包形式返回,返回的是最后一行的值。

正是基于这一点差异它的适用场景稍微与run函数有点不一样。apply一般用于一个对象实例初始化的时候,需要对对象中的属性进行赋值。或者动态inflate出一个XML的View的时候需要给View绑定数据也会用到,这种情景非常常见。特别是在我们开发中会有一些数据model向View model转化实例化的过程中需要用到。

简单使用
var list = ArrayList<Int>();
list = list.apply {
    add(1)
    add(2)
    add(3)
    add(4)
}
Log.d(TAG, "list : $list")

执行后结果

list : [1, 2, 3, 4]

let()

@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block(this)
}

对比上面的run()和apply()等,let()把调用对象直接传入了block(),并返回block(this)的值。

在let中,用it表示引用对象,并可调用其方法,it不可省略。

object.let{
   it.todo()//在函数体内使用it替代object对象去访问其公有的属性和方法
   ...
}

//另一种用途 判断object为null的操作
//表示object不为null的条件下,才会去执行let函数体
object?.let{
   it.todo()
}

var list :ArrayList<Int>? = ArrayList()
list?.let{
    it.add(1)
    it.add(2)
}
print(list)
使用场景

适合用于处理不为null的操作场景。

简单使用
var list = ArrayList<Int>();
list.let {
    it.add(1)
    it.add(2)
    it.add(3)
    it.add(4)
}
Log.d(TAG, "list : $list")

执行结果

list : [1, 2, 3, 4]

with()

@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return receiver.block()
}

with函数不是扩展函数,是将某对象作为函数的参数,在函数块内可以通过this指代该对象,返回值为函数块的最后一行或指定return表达式。

使用场景

适用于调用同一个类的多个方法时,可以省去类名重复,直接调用类的方法或者属性即可,经常用于Android中RecycleView中onBinderViewHolder中,数据model的属性映射到UI上。

简单使用
val student = Student("91大神", 20)
//result返回with()中最后一行或return值
val result = with(student) {
        Log.d(TAG, "name : $name")
        Log.d(TAG, "age : $age")
        91
    }
Log.d(TAG, "result : $result")

执行结果

name : 91大神
age : 20
result : 91

with怎么感觉跟run有点类似,但调用方式不太一样。

val website: String = "91es.com";

//使用run
var name1 = website.run {
    Log.d(TAG, "run : " + isEmpty())
    Log.d(TAG, "run : $length");
    this
};
Log.d(TAG, "run name1 : $name1")

//使用with
var name2 = with(website) {
    Log.d(TAG, "with : " + isEmpty())
    Log.d(TAG, "with : $length");
    this
}
Log.d(TAG, "with name2 : $name2")

执行结果一样

run : false
run : 8
run name1 : 91es.com

with : false
with : 8
with name2 : 91es.com

also()

@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.also(block: (T) -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block(this)
    return this
}

跟let有点像,但最后返回的是this。

使用场景

适用于let函数的任何场景。一般可用于多个扩展函数链式调用。

简单使用
var name = website.also {
    Log.d(TAG, "isEmpty : " + it.isEmpty())
    Log.d(TAG, "length : " + it.length)
}
Log.d(TAG, "also name : $name")

执行结果

isEmpty : false
length : 8
also name : 91es.com

参考文章

  1. 《Kotlin从入门到进阶实战 - 陈光剑 》

  2. Kotlin:常用标准库函数(let、run、with、apply、also)

  3. kotlin常见函数let,with,run,apply,also的使用

 历史上的今天

  1. 2023: 换肤库BinSkin1的使用(0条评论)
  2. 2019: 戴望舒:致萤火(0条评论)
版权声明 1、 本站名称: 91易搜
2、 本站网址: 91es.com3xcn.com
3、 本站内容: 部分来源于网络,仅供学习和参考,若侵权请留言
3、 本站申明: 个人流水账日记,内容并不保证有效

暂无评论

暂无评论...

随机推荐

Android开启Wifi debug调试

前言记录一下开启WiFi debug的方式,记录于此,方便自己查阅。好记性不如烂笔头正文Android 设备开始WiFi调试可以百度[adb wifi apk],网上有很多现成的apk(有广告),前提也是需要root权限的,这里就不多介绍(有兴趣可以看《[代码]开启WiFi调试》)。...

穆旦:古墙

一团灰沙卷起一阵秋风,奔旋地泻下了剥落的古墙,一道晚霞斜挂在西天上,古墙的高处映满了残红。 古墙寂静地弓着残老的腰,驼着悠久的岁月望着前面。一只手臂蜿蜒到百里远,败落地守着暮年的寂寥。 凸凹的砖骨镌着一脸严肃,默默地俯视着广阔的平原;古代的楼阁吞满了荒凉,...

常用的简单monkey测试命令集合

前言Monkey是Android中的一个命令行工具,可以运行在模拟器里或实际设备中。它向系统发送伪随机的用户事件流(如按键输入、触摸屏输入、手势输入等),实现对正在开发的应用程序进行测试。Monkey测试是一种为了测试软件的稳定性、健壮性的快速有效的方法。正文下面整理了一下黑名单和白名单...

adb shell dumpsys audio使用

前言工作中也常用到Android的shell命令adb shell dumpsys audio至于这个命令能做啥,接下来我们简单的讲解一下PS : 本文在Android 9.0上测试的,4.2时dumpsys audio不一定有这么多信息正文dumpsys audio出来的信息有很...

JS监听滚动条位置变化

有时候我们需要监听浏览器中上下滚动的位置来改变一些元素的属性隐藏或者显示,比如91易搜中下拉达到一定高度后搜索框会固定在顶部。(可以前去看看效果)如果我们要实现这效果,就需要监听滚动条的Y轴位置的变化,根据Y轴的位置来改变某些元素的属性值。闲话少说,直接附上代码(下面是改变类heade...

罗伯特·弗罗斯特:未选择的路

黄色的树林里分出两条路,可惜我不能同时去涉足,我在那路口久久伫立,我向着一条路极目望去,直到它消失在丛林深处。 但我却选了另外一条路,它荒草萋萋,十分幽寂,啊,留下一条路等改日再见! 但我知道路径延绵无尽头,恐怕我难以再回返。 也许多少年后在某...