1.官方文档

  英文: https://kotlinlang.org/docs/reference/scope-functions.html

  中文: https://www.kotlincn.net/docs/reference/scope-functions.html

2.简介

  • 在kotlin标准库的Standard.kt 文件中,定义了一系列函数模板。其中的 [ run 、with、let、apply、aloso 、takeIf、takeUnless] 称作用域函数。
  • 它们有个共同点是,最后一个参数都是一个函数指针,当使用 lambda 表达式 方式调用这些函数时,在{ } 内部,可以访问调用者对象而无需其名称,所以叫它们作用域函数。
  • 它们的作用就是让对象上执行一个额外代码,在某些情况下,可以简化代码。
  • 它们生成对象类型的扩展函数(with除外)

  部分代码定义如下:

 public inline fun <T> T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
return this
} /**
* Calls the specified function [block] with `this` value as its argument and returns `this` value.
*
* For detailed usage information see the documentation for [scope functions](https://kotlinlang.org/docs/reference/scope-functions.html#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
} /**
* Calls the specified function [block] with `this` value as its argument and returns its result.
*
* For detailed usage information see the documentation for [scope functions](https://kotlinlang.org/docs/reference/scope-functions.html#let).
*/
@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}

3.内置的几个函数对照表

3.1 对比表

简称 原型 作用 返回值类型 对象的引用名
run

inline fun <R> run(block: () -> R): R

  • 在需要表达式的地方运行语句
  • 无参数运行一段代码
代码块的返回类型 -

inline fun <T, R> T.run(block: T.() -> R): R

对象配置并且计算结果

代码块的返回类型 this
with

inline fun <T, R> with(receiver: T, block: T.() -> R): R

以对象为参数执行一段代码

代码块的返回类型 this
let

inline fun <T, R> T.let(block: (T) -> R): R

  • 对一个非空(non-null)对象执行代码
  • 将表达式作为变量引入为局部作用域中
代码块的返回类型  it 
also

inline fun <T> T.also(block: (T) -> Unit): T

给对象添加附加效果

对象类型 it
apply

inline fun <T> T.apply(block: T.() -> Unit): T

对象配置

对象类型 this
takeIf

inline fun <T> T.takeIf(predicate: (T) -> Boolean): T?

predicate(对象) 执行结果为true返回对象,相反null 对象类型 或 null it
takeUnless

inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T?

!predicate(对象) 执行结果为fase返回对象,相反null 对象类型 或 null it
  • also,apply,takeIf,takeUnless , a和 t 开头的返回对象类型,其它的返回代码块类型。
  • also,let ,  takeIf,takeUnless 引用对象用的是it,其它用this

3.2 注意事项

  适当的场景下,使用作用域函数可以使代码变简洁,但请:

  • 避免过度使用: 这会降低代码的可读性并可能导致错误。
  • 避免嵌套使用
  • 避免链式调用:此时很容易对当前上下文对象及 this 或 it 的值感到困惑。

4.let

4.1 作用

 /**
* Calls the specified function [block] with `this` value as its argument and returns its result.
*
* For detailed usage information see the documentation for [scope functions](https://kotlinlang.org/docs/reference/scope-functions.html#let).
*/
@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
  • 对一个非空(non-null)对象执行 lambda 表达式
  • 将表达式作为变量引入为局部作用域中

4.2 测试

  • 最后一行是返回值

         class Scope2(var name : String)
    
         //1.最后一行是返回值
    val num = .let { Log.e(ScopeTAG, "testLet it = $it")
    }
    Log.e(ScopeTAG, "testLet num = $num")

    结果:

    testLet it = 12
    testLet num = 31
  • 函数式调用

         //2.函数式调用
    fun <T> leeeeeeeeeeeet1(it : T){
    Log.e(ScopeTAG,"testLet let1<T> it = $it")
    }
    13f.let(::leeeeeeeeeeeet1)

    结果

    testLet let1<T> it = 13.0
  • 非空值调用 let

         //3.非空值调用 let
    val flt = 13f.let { }
    Log.e(ScopeTAG, "testLet flt = $flt")

    结果

    testLet flt = 16
  • 非空对象调用

         //4.非空对象调用
    val fullName = Scope2("not-").let {
    val last = "null"
    it.name += last
    Log.e(ScopeTAG, "testLet name append $last ")
    it.name
    }
    Log.e(ScopeTAG, "testLet fullName = $fullName ")

    结果

    testLet name append null
    testLet fullName = not-null
  • 空对象调用

         //5.空对象调用
    val sc2 : Scope2 ? = null
    val name2 = sc2 ?. let {
    it.name += "fff" //虽然sc2 为 null ,但是由于是sc2 ?. 调用,所以在{}内不用以 ?.方式使用it
    }
    Log.e(ScopeTAG, "testLet name2 = $name2 ")

    结果

    testLet name2 = null
  • 将表达式作为变量引入为局部作用域中

         //6.将表达式作为变量引入为局部作用域中
    + ( * ) .let {
    Log.e(ScopeTAG, "testLet 1 + (2 * 300) = $it ")
    }

    结果

    testLet 1 + (2 * 300) = 600 
  • 静态类或者伴生对象.let,访问静态成员
         //7.静态类或者伴生对象.let,访问静态成员
    Int.let {
    //对Int的伴生对象调用let
    Log.e(ScopeTAG, "testLet Int.MIN_VALUE = ${it.MIN_VALUE} , SIZE_BYTES = ${it.SIZE_BYTES} , it = $it")
    }

    结果

    testLet Int.MIN_VALUE = -2147483648 , SIZE_BYTES = 4 , it = kotlin.jvm.internal.IntCompanionObject@e99cd85

5.apply

5.1 作用

 /**
* Calls the specified function [block] with `this` value as its receiver and returns `this` value.
*
* For detailed usage information see the documentation for [scope functions](https://kotlinlang.org/docs/reference/scope-functions.html#apply).
*/
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
return this
}

  主要用来对象配置

5.2 测试

  • 配置对象

         class Scope3 {
    var name = ""
    var age =
    var first = ""
    var last = ""
    var address = ""
    var phone = "" override fun toString(): String {
    return "name = $name,age = $age,first = $first,last = $last,address = $address,phone = $phone"
    }
    }
    //1.主要用来配置对象
    val sc3 = Scope3().apply {
    name = "eot"
    age =
    first = "li"
    last = "per"
    address = "ooeoeooe"
    phone = "13xxxxxxx"
    } Log.e("scope_test","testApply sc3 : $sc3")

    结果

    testApply sc3 : name = eot,age = 12,first = li,last = per,address = ooeoeooe,phone = 13xxxxxxx
  • 静态类或有内部静态类可以使用类名.apply{} ,没有静态内部类的不支持
     class Apply{
    companion object{
    var value =
    override fun toString(): String {
    return "value = $value"
    }
    }
    }
    object Apply2{
    var value =
    override fun toString(): String { return """value = $value""" }
    }
    class Apply3{
    object Static1{
    var value1 =
    override fun toString(): String { return """value1 = $value1""" }
    }
    object Static2{
    var value2 =
    override fun toString(): String { return """value2 = $value2""" }
    }
    } //2.静态类或有内部静态类可以使用类名.apply{} ,没有静态内部类的不支持
    val a0 = Apply.apply { value = }
    Log.e(ScopeTAG,"testApply a0 : $a0") val a4 = Apply2.apply { value = }
    Log.e(ScopeTAG,"testApply s4 : $a4") val a3 = Apply3.Static1.apply { value1 = }
    Log.e(ScopeTAG,"testApply a3 : $a3")

    结果

    testApply a0 : value = 11
    testApply s4 : value = 55
    testApply a3 : value1 = 66
  • kotlin内置常用类都有静态内部类
         val a1 = Int.apply {
    
              *
    }
    val a2 = String.apply { """hello"""}
    Log.e(ScopeTAG,"testApply a1 : $a1 ,a2 : $a2")

    结果

    testApply a1 : kotlin.jvm.internal.IntCompanionObject@6a122e8 ,a2 : kotlin.jvm.internal.StringCompanionObject@2aebd01
  • 没有静态内部类的不支持,编译不过
         //3.没有静态内部类的不支持
    class Apply4 { var value = }
    val a6 = Apply4.apply { value = 77 }
    Log.e(ScopeTAG,"testApply a6 : $a6")

    结果: 编译不过

6.run

6.1 作用

  这个函数有两个版本

  全局函数版本

 /**
* Calls the specified function [block] and returns its result.
*
* For detailed usage information see the documentation for [scope functions](https://kotlinlang.org/docs/reference/scope-functions.html#run).
*/
@kotlin.internal.InlineOnly
public inline fun <R> run(block: () -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}

  扩展函数版本

 /**
* Calls the specified function [block] with `this` value as its receiver and returns its result.
*
* For detailed usage information see the documentation for [scope functions](https://kotlinlang.org/docs/reference/scope-functions.html#run).
*/
@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}

  全局函数版本: 运行一段代码,无参数。

  扩展函数版本 :  对象配置并且计算结果

6.2 测试

  • 全局函数版

         //1.全局函数版
    run {
    Log.e(ScopeTAG,"testRun 全局函数版: 运行代码")
    }
    val i3 = * + run { Log.e(ScopeTAG,"testRun 全局函数版: 在表达式中运行语句"); } +
    Log.e(ScopeTAG,"testRun 全局函数版: i3 = $i3 (122 * 2 + 23 + 34)")

    结果

    testRun 全局函数版: 运行代码
    testRun 全局函数版: 在表达式中运行语句
    testRun 全局函数版: i3 = 301 (122 * 2 + 23 + 34)
  • 扩展函数版本
         //2.扩展函数版本
    class A(var name : String){ fun query() : String = "name = $name" } val result = A("null").run {
    this.name = "r1"
    query()
    }
    Log.e(ScopeTAG,"testRun result = $result")

    结果

    testRun result = name = r1

7.with

7.1 作用

 /**
* Calls the specified function [block] with the given [receiver] as its receiver and returns its result.
*
* For detailed usage information see the documentation for [scope functions](https://kotlinlang.org/docs/reference/scope-functions.html#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()
}

 以对象为参数,执行以下操作

7.2 测试

 fun testWith(){
//1.全局函数版
with() {
Log.e(ScopeTAG,"testWith this = $this")
} //2.扩展函数版本
class A(var name : String) val w1 = A("null")
Log.e(ScopeTAG,"testWith r1.name = ${w1.name}")
with(w1) {
this.name = "w1"
Log.e(ScopeTAG,"testWith name = $name")
} //3.同理,对静态类或者有伴生对象的类
with(Int){
Log.e(ScopeTAG, "testWith Int.MIN_VALUE = ${this.MIN_VALUE} , SIZE_BYTES = ${this.SIZE_BYTES} , it = $this")
}
with(Apply2){
Log.e(ScopeTAG, "testWith Apply2.value = ${this.value} , this = $this")
} //4.空对象
val nullInt : Int? = null
with(nullInt){
Log.e(ScopeTAG, "testWith nullInt = $this")
} //5.在表达式中
val ret = + * with(){ //注意优先级 12 + (29 * 6) = 186
this *
}
Log.e(ScopeTAG, "testWith ret = $ret") }

 结果

testWith this = 3
testWith r1.name = null
testWith name = w1
testWith Int.MIN_VALUE = -2147483648 , SIZE_BYTES = 4 , it = kotlin.jvm.internal.IntCompanionObject@3222e75
testWith Apply2.value = 55 , this = value = 55
testWith nullInt = null
testWith ret = 186

8.also

8.1 作用

 /**
* Calls the specified function [block] with `this` value as its argument and returns `this` value.
*
* For detailed usage information see the documentation for [scope functions](https://kotlinlang.org/docs/reference/scope-functions.html#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
}

  当你在代码中看到 also 时,可以将其理解为“并且用该对象执行以下操作”。

8.2 测试

 object Also{ var value =  ; override fun toString(): String { return "value = $value" } }

 fun testAlso(){
//1,对象并且执行的
val name = "testAslo-hello"
val sub = name.substringAfter("-").also {
it.toUpperCase()
}
Log.e(ScopeTAG, "testAlso sub = $sub") //2,静态类、伴生对象
val a1 = Int.also { }
Log.e(ScopeTAG, "testAlso a1 = $a1")
val a2 = Also.apply { value = }
Log.e(ScopeTAG, "testAlso a2 = $a2") //3,空对象
val nil : Also? = null
nil?.also {
it.value =
}
Log.e(ScopeTAG, "testAlso nil = $nil") }

结果

testAlso sub = hello
testAlso a1 = kotlin.jvm.internal.IntCompanionObject@6a122e8
testAlso a2 = value = 39
testAlso nil = null 

9. takeIf、takeUnless

9.1 作用

 /**
* Returns `this` value if it satisfies the given [predicate] or `null`, if it doesn't.
*/
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? {
contract {
callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
}
return if (predicate(this)) this else null
} /**
* Returns `this` value if it _does not_ satisfy the given [predicate] or `null`, if it does.
*/
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? {
contract {
callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
}
return if (!predicate(this)) this else null
}

  takeIf 以对象为参数,判断它是否满足某个条件,满足返回对象本身,否则返回null

  takeUnless 与takeIf相反,判断是否不满足

9.2 测试

 fun testTake(){

     val now = SystemClock.elapsedRealtime()
val tif = now.takeIf {
Log.e(ScopeTAG,"testTake takeIf now = $it")
it % == 0L
}
Log.e(ScopeTAG,"testTake tif = $tif") val tus = now.takeUnless {
Log.e(ScopeTAG,"testTake takeUnless now = $it")
it % == 0L
}
Log.e(ScopeTAG,"testTake tus = $tus")
}

结果

testTake takeIf now = 5769124
testTake tif = 5769124
testTake takeUnless now = 5769124
testTake tus = null
 

对象配置并且计算结果

kotlin 作用域函数 : let、run、with、apply、 also、takeIf、takeUnless的更多相关文章

  1. Kotlin 之 let、with、run、apply、also 函数的使用

    一.内联拓展函数 let let 扩展函数的实际上是一个作用域函数,当你需要去定义一个变量在一个特定的作用域范围内,let函数的是一个不错的选择:let函数另一个作用就是可以避免写一些判断null的操 ...

  2. 浅谈JavaScript的函数的call以及apply

    我爱撸码,撸码使我感到快乐!大家好,我是Counter.今天就来谈谈js函数的call以及apply,具体以代码举例来讲解吧,例如有函数: function func(a, b) { return a ...

  3. Kotlin 的函数定义和使用 (译文 转)

    Kotlin 的函数定义和使用 函数声明Kotlin 中的函数使用 fun 关键字声明 fun double(x: Int): Int {}函数用法调用函数使用传统的方法 val result = d ...

  4. R中的高效批量处理函数(lapply sapply apply tapply mapply)(转)

    转自:http://blog.csdn.net/wa2003/article/details/45887055 R语言提供了批量处理函数,可以循环遍历某个集合内的所有或部分元素,以简化操作. 这些函数 ...

  5. 初识Kotlin之函数

    本章通过介绍Kotlin的基本函数,默认参数函数,参数不定长函数,尾递归函数,高阶函数,Lamdba表达式.来对Kotlin函数做进一步了解.将上一篇的Kotlin变量的知识得以运用.Kotlin变量 ...

  6. kotlin之函数的范围和泛型函数

    kotlin 中函数可以定义为局部函数,成员函数以及扩展函数 局部函数:就是嵌套在函数内的函数 成员函数就是定义在类或者对象之内的函数 泛型函数就是函数可以带有泛型参数,可通过尖括号来指定

  7. Kotlin 中类函数

    在kotlin中函数可以在类外部定义也可以在类内部定义,前者即为全局函数,后者,是类成员函数,语法一样 package loaderman.demo class Person { fun demo(n ...

  8. javascript中函数的call,apply及bind方法

    call 方法调用一个对象的一个方法,以另一个对象替换当前对象.call([thisObj[,arg1[, arg2[,  [,.argN]]]]])参数thisObj可选项.将被用作当前对象的对象. ...

  9. 云平台项目--学习经验--回调函数中call和apply

    Js中可以通过call和apply来代替另一个对象调用一个方法,将一个函数对象上下文从初始上下文改变为thisObj指定的新对象.简而言之,改变函数执行的上下文,而call和apply的基本区别在于他 ...

随机推荐

  1. OJ评测状态

    Pending/Waiting 排队等待中 Pending Rejudge 答案重判中 Compiling 正在编译 Running/Judging 运行判断中 Accepted(AC) 程序通过 C ...

  2. 【HEOI2015】公约数数列 题解(分块)

    前言:毒瘤数据结构题,半个下午都在搞它了…… --------------------------- 题目链接 题目大意:给定一个长度为$n$的序列,有两种操作:1.把$a_x$的值改成$y$.2.求 ...

  3. SpringMvc响应数据和结果视图

    响应数据和结果视图 返回值分类 字符串 controller 方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址. //指定逻辑视图名,经过视图解析器解析为 jsp 物理路径:/WEB ...

  4. (数据科学学习手札92)利用query()与eval()优化pandas代码

    本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 利用pandas进行数据分析的过程,不仅仅是计算 ...

  5. C#LeetCode刷题-链表

    链表篇 # 题名 刷题 通过率 难度 2 两数相加   29.0% 中等 19 删除链表的倒数第N个节点   29.4% 中等 21 合并两个有序链表 C#LeetCode刷题之#21-合并两个有序链 ...

  6. three.js 着色器材质内置变量

    这篇郭先生说一下three.js着色器的内置变量,分别是 gl_PointSize:在点渲染模式中,控制方形点区域渲染像素大小(注意这里是像素大小,而不是three.js单位,因此在移动相机是,所看到 ...

  7. Mybatis中<![cdata[ ]]>

    1.<![cdata[ ]]>介绍 <![cdata[ 内容 ]]>是一种xml语法,在CDATA标记中的信息被解析器原封不动地传给应用程序,并且不解析该段信息中的任何控制标记 ...

  8. C++ STL sort 函数的用法

    sort 在 STL 库中是排序函数,有时冒泡.选择等 $\mathcal O(n^2)$ 算法会超时时,我们可以使用 STL 中的快速排序函数 $\mathcal O(n \ log \ n)$ 完 ...

  9. Java并发--三大性质

    一.多线程的三大性质 原子性:可见性.有序性 二.原子性 原子性介绍 原子性是指:一个操作时不可能中断的,要么全部执行成功要么全部执行失败,有着同生共死的感觉.即使在多线程一起执行的时候,一个操作一旦 ...

  10. C++类和对象的封装 点和圆的案例

    主要练习 :在类中可以让另一个类作为本类的成员. 案例:判断点和圆的位置关系. 一.第一种直接方法 using namespace std; #include <iostream> cla ...