作用域函数(apply、also、run、with、let)

 标准库中的作用域函数

在 Standard.kt 标准库中提供了一些便捷的内置高阶函数,可以帮助我们写出更简洁高效的代码。这些函数都是在一个对象上执行一个代码块,形成一个临时作用域可以访问该对象而无需其名称,不同的是这个对象在代码块中如何使用以及整个表达式的返回值是什么。由于是 inline 内联函数,优化了调用函数出入栈的性能开销。

内置高阶函数说明使用场景

apply

  

     官方apply
        inline fun <T> T.apply(block: T.() -> Unit): T {
        //block()
        //return this
        //或者
        block.invoke(this) //这里将接受者对象this(T)作为隐士参数 传递给lambda  没有其他的额外参数传递
        return  this   //返回 接受者对象this(T)

        }

在调用处:调用该对象this的类成员,返回该对象。

参数: T.() :在applay源码里将接受者对象this(T)作为隐士参数 传递给lambda,没有其他的参数。

在lambda表达式实现作用域内,隐士参数 this,使用this可以直接访问调用者对象T(自定义对象/this)的类成员

返回值: T:即返回调用者对象(自定义对象/this)本身,可基于原始对象进行链式调用。

对该对象的成员属性和成员函数进行一系列的调用,创建实例并配置(对已有的实例配置选with)。由于最后返回该对象可以链式调用,一次操作过多可以将同类型操作分批写在不同代码块里让视觉上更直观。
with

 inline fun <T, R> with(receiver: T, block: T.() -> R): R {
        //var result:R = receiver.block()
        //return  result
  var result:R =block.invoke(receiver)
 return  result
        }

参数: T.() :在with源码可知,

即 this,直接访问调用者对象(自定义对象/this)的类成员(配置自身)返回值

返回值:R:即返回一个值,可基于新值进行链式调用。

对该对象的成员属性和成员函数进行一系列的调用,对已有的实例进行配置(创建并配置选apply)。
also

   官方also
        public inline fun <T> T.also(block: (T) -> Unit): T {
        //block(this)
        //return this
        //或者
        block.invoke(this) //没有返回值
        return this       // 把接受者对象T this 进行返回
        }

将该对象当做参数使用,返回该对象。

参数:(T) :通过also源码可知将调用者对象this当作lambda表达式的参数进行回调

调用处:在调用处通过lambda表达式具体实现通过lambda的参数it (调用者对象)调用调用者对象的成员或者做额外的事。

返回值:T:即返回调用者对象本身,可基于原始对象进行链式调用。

将该对象当作参数进行一系列操作。由于最后返回该对象可以链式调用,一次操作过多可以将同类型操作分批写在不同代码块里让视觉上更直观。
let

   inline fun <T, R> T.let(block: (T) -> R): R {
     // val result:R = block(this)
     //  return result
     val result:R =block.invoke(this)
     return result
     }

将该对象当做参数使用,返回Lambda的值。

参数:(T) :在let源码可知 把调用者对象this作为参数T进行回调

在调用处,通过lambda表达式具体实现,lambda的参数it(默认值)就是当前对象T

返回值:R:在let源码可知,把一个新值R作为返回值.

在调用处通过lambda表达式具体实现,把lamba最后一行作为返回值。

①将该对象当作参数进行一系列操作;

②对可空类型对象的多次调用做统一的 null 判断。

run

   public inline fun <T, R> T.run(block: T.() -> R): R {
  // return block()
  //或者
  val result:R = block.invoke(this)
  return result
  }

调用该对象的类成员,返回Lambda的值。

参数: T.() :通过run源码可知,将接受者对象this 传递给lambda表达式的参数

在调用处:在lambda表达式作用域的参 this,通过this直接访问调用者对象(自定义对象/this)的类成员(配置自身)返回值

返回值:R:即返回一个值,可基于新值进行链式调用。

run

 inline fun <R> run (block: () -> R): R {
    // return block()
    //或者
    val result:R = block.invoke()
    return result
    }   

执行若干代码,返回Lambda的值。不是扩展函数。

  

apply函数

对象实例初始化时需要对对象中的属性进行赋值 & 返回该对象

  官方apply
          inline fun <T> T.apply(block: T.() -> Unit): T {
        //block()
        //return this
        //或者
        block.invoke(this) //这里将接受者对象this(T)作为隐士参数 传递给lambda  没有其他的额外参数传递
        return  this   //返回 接受者对象this(T)

        }
         

apply与run函数类似,但区别在于返回值不同:

run函数:返回最后一行的值 / 表达式

apply函数:返回传入的对象的本身

 package com.my.runalone_higherorderfunction.bean

import android.util.Log

class Person(var name_:String?="上帝",var age_:Int?=0) {
    val  TAG="HigherOrderFunctionSuspendActivity"

    var name:String? = name_
    var age:Int? = age_
    var sex:Int = 0

    override fun toString(): String {
        return  "name:$name, age:$age, sex:$sex"
    }

    public fun  study(){
        Log.e(TAG, "$name is studying" )
     }

}


class HigherOrderFunctionSuspendActivity  : ComponentActivity() {

 override   fun onCreate(savedInstanceState: Bundle?){
         /**
       * 官方apply
          inline fun <T> T.apply(block: T.() -> Unit): T {
        //block()
        //return this
        //或者
        block.invoke(this) //这里将接受者对象this(T)作为隐士参数 传递给lambda  没有其他的额外参数传递
        return  this   //返回 接受者对象this(T)

        }
         */

 val person= Person(name_="张三")
 person.apply(block={
      Log.e(TAG, "apply 输出结果this=${this.toString()}") //apply 输出结果this=name:张三, age:0, sex:0
      //直接访问Person的属性
         this.age=20 //this可以省略
        this.sex=1   //this可以省略

  }).apply {
      this.study()  //张三 is studying
  }
 

}

}

 with函数

调用同一个对象的多个方法 / 属性时,可以省去对象名重复,直接调用方法名 / 属性即可

需要调用同一个对象的多个方法 / 属性

     /**
        inline fun <T, R> with(receiver: T, block: T.() -> R): R {
        //var result:R = receiver.block()
        //return  result
        var result:R = block.invoke(receiver)
        return  result
        }
         */

 val withResult:Int = with(receiver = person, block = {
            Log.e(TAG, "with 输出当前对象this=${this} ")//  with 输出当前对象this=name:张三, age:20, sex:1
            this.name_ = "张四"
            this.age_ = 21
            this.sex = 0
            123//把lambda最后一行作为返回值
        })

        Log.e(TAG, "withResult=${withResult}") // withResult=123

自定义myWith1/2/3/4/5/6/7(...)函数

Extend.kt

 inline fun <T, R> myWith1(receiver: T, block: T.(Any) -> R): R {
        var result:R = block.invoke(receiver,101)
       return  result
  }
 
 
inline fun <T, R> T.myWith2( block: T.(Any) -> R): R {
    var result:R = block.invoke(this,"angleBody")
    return  result
}
 
 
 
 
inline fun <T, R> T.myWith3( block: T.(Any) -> R): R {
    var result:R = block.invoke(this,12)
    return  result
}
 
 
 
inline fun <T, R>   myWith4( block: (T,Any) -> R): R {
    val person= Person(name_="NIUBI",age_=233)
    var result:R = block.invoke( person as T   ,"niubi")
    return  result
}
 
 
val  TAG="HigherOrderFunctionSuspendActivity"
inline fun <T, R>   T.myWith5( block: T.(T,Any) -> R): R {
    Log.e(TAG, "T.myWith5 输出当前对象this=${this}") //T.myWith5 输出当前对象this=name:天使, age:12, sex:1
    val person= Person(name_="newPer",age_=23) as T
    var result:R = block.invoke(this,person,true)
    return  result
}
 
 
 
 
inline fun<T,R> T.myWith6(block:(T)->R):R{
    // val result:R = block(this)
    //  return result
    val result:R = block.invoke(this)//b把接受者对象this 作为参数进行传递 回调给lambda
    return result
}
 
 
inline fun <T, R> T.myWith7( block: T.(T) -> R): R {
//var result:R = receiver.block()
//return  result
    var result:R = block.invoke(this,this)
    return  result
}
 
class HigherOrderFunctionSuspendActivity  : ComponentActivity() {
 
 override   fun onCreate(savedInstanceState: Bundle?){
 
    val myWith1Result :String =  myWith1(receiver = person,block={
           Log.e(TAG,"myWith1 输出当前对象this=${this}, it=$it") //myWith1 输出当前对象this=name:张三, age:20, sex:1, it=101
            this.name="张四"
            this.age=21
            "Androider" //把lambda最后一行作为返回值
       })
        Log.e(TAG, "myWith1Result=${myWith1Result}") //myWith1Result=Androider
 
        val myWith2Result :Person = person.myWith2(block={
            Log.e(TAG,"myWith2 输出当前对象this=${this}, it=$it") //myWith2 输出当前对象this=name:张四, age:21, sex:1, it=angleBody
            this.name=it as String
            this.age=22
            this   //把lambda最后一行作为返回值
        })
        Log.e(TAG, "myWith2Result=${myWith2Result}") //myWith2Result=name:angleBody, age:22, sex:1
 
 
        val myWith3Result: String= 100.myWith3(block = {
            Log.e(TAG, "myWith3 输出当前对象this=${this}, it=$it")  //myWith3 输出当前对象this=100, it=1.2
            "FM.1080" //把lambda最后一行作为返回值
        })
 
        Log.e(TAG, "myWith3Result=${myWith3Result}") //myWith3Result=FM.1080
 
        val myWith32Result: Person = person.myWith3(block = {
            Log.e(TAG, "myWith3 输出当前对象this=${this}, it=$it")  //myWith3 输出当前对象this=name:angleBody, age:22, sex:1, it=12
            this.name="天使"
            this.age=it as Int
            this //把lambda最后一行作为返回值
        })
 
        Log.e(TAG, "myWith32Result=${myWith32Result}") //myWith32Result=name:天使, age:12, sex:1
 
 
 
 
 
       val myWith4Result:Int =  myWith4(block={pp:Person,str->
           Log.e(TAG, "myWith4 输出当前对象pp=${pp}, str=$str") //myWith4 输出当前对象pp=name:NIUBI, age:233, sex:0, str=niubi
           2024  //把lambda最后一行作为返回值
       })
 
        Log.e(TAG, "myWith4Result=${myWith4Result}") //myWith4Result=2024
 
 
 
        Log.e(TAG, " 输出当前对象person=${person.toString()}")  // 输出当前对象person=name:天使, age:12, sex:1
        val myWith5Result:Boolean =  person.myWith5(block={newP:Person,bo:Any->
              Log.e(TAG, "myWith5  this=${this},输出当前对象newP=${newP},bo=$bo") //myWith5  this=name:天使, age:12, sex:1,输出当前对象newP=name:newPer, age:23, sex:0,bo=true
             var isChild:Boolean=false
             if(bo as Boolean){
                 isChild=true
             }
               isChild  //把lambda最后一行作为返回值
         })
        Log.e(TAG, "myWith5Result=${myWith5Result}") //myWith5Result=true
 
 
 
        val myWith6Result:Person  =  person.myWith6(block={
              Log.e(TAG, "myWith6  输出lambda的参数it=${it}") //myWith6  输出lambda的参数it=name:天使, age:12, sex:1
             it.name="llong"
              it  //把lambda最后一行作为返回值
          })
 
        Log.e(TAG, "myWith6Result=${myWith6Result}") // myWith6Result=name:llong, age:12, sex:1
 
 
        val myWith7Result:String  =  person.myWith7(block={
                   Log.e(TAG, "myWith7  输出lambda的参数this=${this}, it=${it}") //myWith7  输出lambda的参数this=name:llong, age:12, sex:1, it=name:llong, age:12, sex:1
                    "kotlin"
               })
 
        Log.e(TAG, "myWith7Result=${myWith7Result}") //myWith7Result=kotlin
 
 
}
 
}

also函数

     
        官方also
        public inline fun <T> T.also(block: (T) -> Unit): T {
        //block(this)
        //return this
        //或者
        block.invoke(this) //没有返回值
        return this       // 把接受者对象T this 进行返回
        }
          

also函数与let函数的区别:

let函数:返回值 = 最后一行 / return的表达式

also函数:返回值 = 传入的对象的本身

 class HigherOrderFunctionSuspendActivity  : ComponentActivity() {

 override   fun onCreate(savedInstanceState: Bundle?){

        /**
        官方also
        public inline fun <T> T.also(block: (T) -> Unit): T {
        //block(this)
        //return this
        //或者
        block.invoke(this) //没有返回值
        return this       // 把接受者对象T this 进行返回
        }
         */

  val person= Person(name_="张三")
   //使用also后(使用it调用更便于阅读,分类隔开写代码视觉上更直观)
        person.also(block={
            //没有指定参数名字,必须用it代指参数   it:Person = person
            Log.e(TAG,"also   输出lambda的参数it=$it")
            it.name="liuliang"
            it.age=20
            it.sex=0
            Log.e(TAG, "输出结果it=${it.toString()}" )  //输出结果it=name=liuliang, age=20, sex=0

        })   //点 左侧依然是person 对象 点右侧链式调用
            .also {
            it.study()   //liuliang is studying
        }

}

 let函数

class HigherOrderFunctionSuspendActivity  : ComponentActivity() {

 override   fun onCreate(savedInstanceState: Bundle?){

    /**
     inline fun <T, R> T.let(block: (T) -> R): R {
     // val result:R = block(this)
     //  return result
     val result:R =block.invoke(this)
     return result
     }
     */
 //使用let后(使用it更便于阅读)
 //使用let后(只需要使用一次安全调用符)
        val letResult :Person? = person?.let(block = {
         Log.e(TAG,"let1 输出当前对象it=$it")  //let1 输出当前对象it=name:liuliang, age:20, sex:0
         it.name = "李四"
            it.age = 29
            it.sex = 2
            //Log.e(TAG, "输出结果it=${it.toString()}"
            it //把lambda最后一行作为返回值
        })
        Log.e(TAG, "let1 输出结果letResult=${letResult}" ) //let1 输出结果letResult=name:李四, age:29, sex:2

        val letResult2 :String? =    letResult?.let(block={
            Log.e(TAG,"let2 输出当前对象it=$it") //let2 输出当前对象it=name:李四, age:29, sex:2
            it.name = "王五"
            "fmf" //把lambda最后一行作为返回值
        })

        Log.e(TAG, "let2 输出结果letResult2=${letResult2}" ) //let2 输出结果letResult2=fmf

}

}
 

 run函数

结合了let、with两个函数的作用,

1.调用同一个对象的多个方法 / 属性时,可以省去对象名重复,直接调用方法名 / 属性即可

2.定义一个变量在特定作用域内

3.统一做判空处理

/**
  public inline fun <T, R> T.run(block: T.() -> R): R {
  // return block()
  //或者
  val result:R = block.invoke(this)
  return result
  }
 */ 


  val runResult:String = person.run(block = {
   Log.e(TAG, "run 输出当前对象this=$this") //  run 输出当前对象this=name:王五, age:29, sex:2
            "run run go go" //把lambda最后一行作为返回值
        })
        Log.e(TAG, "run 输出结果runResult=${runResult}" ) // run 输出结果runResult=run run go go

自定义MyRun函数

 Extend.kt

  inline fun <T, R> T.myRun(block: T.() -> R): R {
     // return block()
      //或者
      val result:R = block.invoke(this)
       return result
  }


inline fun <T, R> T.myRun3(block:  () -> R): R {
    // return block()
    //或者
    val result:R = block.invoke()
    return result
}

inline fun <R> myRun4(block: () -> R): R {
    // return block()
    //或者
    val result:R = block.invoke()
    return result
}


class HigherOrderFunctionSuspendActivity  : ComponentActivity() {

 override   fun onCreate(savedInstanceState: Bundle?){

  val myRunResult:Boolean = person.myRun(block = {
            Log.e(TAG, "myRun 输出当前对象this=$this") //myRun 输出当前对象this=name:王五, age:29, sex:2
            false //把lambda最后一行作为返回值
        })

        Log.e(TAG, "myRun 输出结果myRunResult=${myRunResult}" ) //myRun 输出结果myRunResult=false


        val myRun3Result:Boolean = person.myRun3(block = {
            person.age = 20
            person.sex = 1
            true //把lambda最后一行作为返回值
        })
        Log.e(TAG, "myRun3Result 输出结果myRun3Result=${myRun3Result}" ) //myRun3Result 输出结果myRun3Result=true


        val myRun4Result:Int = myRun4(block = {
            456   //把lambda最后一行作为返回值
        })

        Log.e(TAG, "myRun4 输出结果myRun4Result=${myRun4Result}" ) //myRun4 输出结果myRun4Result=456


}

}

其他标准库函数

repeat

原理:将 action 函数执行 times 次。第一次的索引为0。

 public inline fun repeat(times: Int, action: (Int) -> Unit) {
              for (index in 0 until times) {
                 // action(index)
                  //或者
                  //通过源码可知 ,遍历集合tiems每一次, invoke传递一次参数index
                  action.invoke(index)
              }
          }

 repeat(times=6,action={
     // 输出lambda表达式参数it
     Log.e(TAG, "A$it")  //A0,A1,A2,A3,A4,A5

 })

takeIf 

说明:lambda 返回 true 则返回调用者对象,否则返回 null。

场景:判断是否满足条件,再决定是否赋值或者执行操作。和 if 相似,作用于实例上避免了临时变量赋值的麻烦。

 inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? {
                //return if (predicate(this)) this else null
               val result:Boolean = predicate.invoke(this)//将调用者T=this(隐士)作为lambda表达式的参数就行回调
              // 返回Boolean类型 :返回 true 则返回调用者对象this,否则返回 null
                if(result){
                     return this
                 }
               return null
          }

  val num6:Int=5
        val takeIfResult = num6.takeIf(predicate = {
            Log.e(TAG, "takeIf 输出lambda的回调参数it=$it") //takeIf 输出lambda的回调参数it=5
            it > 3 //把lambda最后一行 it > 3=true  作为返回值 回调给takeIf源码
        })

        Log.e(TAG, "输出结果takeIfResult=${takeIfResult}") //输出结果takeIfResult=5


        val num62:Int=5
        val takeIfResult2 = num62.takeIf(predicate = {
            Log.e(TAG, "takeIf 输出lambda的回调参数it=$it") //takeIf 输出lambda的回调参数it=5
            it > 6 // 把lambda最后一行 it > 6=false 作为返回值 回调给takeIf源码
        })

        Log.e(TAG, "输出结果takeIfResult2=${takeIfResult2}") //输出结果takeIfResult2=null

takeUnless 

原理:功能和 takeIf 相反,predicate 返回 false 则返回调用者对象,否则返回 null。

TODO 

用来标记待办,会抛异常,可以指定异常原因。

public inline fun TODO(): Nothing = throw NotImplementedError()
 
public inline fun TODO(reason: String): Nothing = throw NotImplementedError("An operation is not implemented: $reason")

 鸣谢

Kotlin - 作用域函数(apply、also、run、with、let)_kotlin let run apply with函数-CSDN博客

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值