Kotlin中的特殊函数简介

Android2024年8月30日 pm4:48发布2周前更新 91es.com站长
99 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、 本站内容: 部分来源于网络,仅供站长学习和参考,若侵权请留言

暂无评论

暂无评论...

随机推荐

Thread中断简单介绍

前言简答记录一下Thread中断相关的内容。记录一下,方便自己查阅。正文Thread中断主要涉及如下几个方法:interrupt()isInterrupted()interrupted()下面单独介绍一下。interrupt()interrupt()使线程中断。...

SQLite中的数据排序简介

前言本文摘抄,记录Sqlite使用不同的排序方式对各种数据类型进行排序。方便自己查阅和使用。正文下面只摘抄了一部分。普通排序文本类型(Text/String):按字典顺序排序:使用ORDER BY语句,并在字段名称后添加COLLATE NOCASE。例如:SELECT * FR...

为TV屏适配GridView选中并实现缩放动画

前言GridView自定义话选中框,并进行缩放处理,试用于展示图片和视频缩略图。好记性不如烂笔头正文原理在监听onKeyUp处理,此时选中的Item由Android处理完了,我们只需要刷新界面当old view跟new view不一样时才需要缩放处理。对图片缩放一定要用属性动画,对...

Android 6.0 Settings源码简单分析之蓝牙(2)

上一篇《Android 6.0 Settings源码简单分析之蓝牙(1)》我们只是简单的介绍了蓝牙的界面和流程的启动,讲得比较粗糙,这次我们继续深入讨论蓝牙,设计Framework的代码源码:Android 6.0应用:Settings 和 Framework(权且看做一个应用吧^_^...

Android应用启动时出现白屏或者黑屏问题的简介

前言Android系统上,当启动应用时存在闪白屏或者黑屏,这种问题很常见。产生原因:当系统启动一个APP时,zygote进程会首先创建一个新的进程去运行这个APP,但是进程的创建是需要时间的,在创建完成之前,界面是呈现假死状态的,因为用户会以为没有点到APP而再次点击,这极大的降低用户体验,...

ListView item布局简单记录

前言简单记录一下ListView中ItemLayout正文下面布局按下后文字和图片都按按下效果颜色变化。隐藏内容!付费阅读后才能查看!¥2 ¥3多个隐藏块只需支付一次付费阅读参考文章