Kotlin 学习笔记(十一)Kotlin中的库函数: run、with、let、also和apply

前言
本博客为本人学习笔记,如有不对的地方,劳请在评论区指出,望海涵

前提
Kotlin,支持闭包(block),如果函数中最后一个参数为闭包,那么最后一个参可以不写在括号中,而写在括号后面,如果只有一个参数,括号也可以去掉。(这个概念比较重要后边的 源码理解都会用到)

1. with 函数 和 run 函数

  希望通过两个函数对比可以加深我们的学习印象

@kotlin.internal.InlineOnly
public inline fun  with(receiver: T, block: T.() -> R): R = receiver.block()

  with函数 接收一个 T 类型的对象和一个被作为扩展函数的函数。这个方法主要是让这个t对象去执行body函数。因为第二个参数是一个函数,所以第二个函数可以放在圆括号外边。我们可以在第二个参数里面创建代码块,在这个代码块里可以使用 this和直接访问public的方法和属性,返回最后一行结果。

@kotlin.internal.InlineOnly
public inline fun  T.run(block: T.() -> R): R = block()

   run函数也是一个扩展函数。 和apply函数很像,只不过run函数是使用最后一行的返回,apply返回当前自己的对象this。(apply函数我们最后讲)

我们通过 java 和 kotlin 两种方式进行对比

// java

TextView text = findViewById(R.id.tv_text)
text.("ymc")
text.setTextSize(23)

  以上是java 代码,我们再通过kotlin代码分别写出 with 和 run 函数的适用方式

// kotlin

// with 函数
with(R.id.tv_text) {
    tv_text.text = "ymc"
    tv_text.textSize = 23f
}

// run 函数
R.id.tv_text.run {
  	tv_text.text = "ymc"
	tv_text.textSize = 23f
}

kotlin code

protected void onCreate(@Nullable Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      this.setContentView(2131296283);
      int var2 = -1100088;
      ((TextView)this._$_findCachedViewById(id.tv_text)).setText((CharSequence)"ymc");
      ((TextView)this._$_findCachedViewById(id.tv_text)).setTextSize(23.0F);
      var2 = -1100088;
      ((TextView)this._$_findCachedViewById(id.tv_text)).setText((CharSequence)"ymc");
      ((TextView)this._$_findCachedViewById(id.tv_text)).setTextSize(23.0F);
   }

  上面两段代码实现的功能是一样的,转换后的kotlin code 也都一样,相比与 java ,kotlin的代码更加简洁。
  with / run 函数中的参数是一个对象,我们可以带方法中直接引用对象的公有属性或者公有方法,而不用使用方法名。

不同:

  1. with 函数为普通函数,run 函数则为扩展函数
  2. 可能为空的时候函数的简洁性
  3. 因为run函数是let,with两个函数结合体,准确来说它弥补了let函数在函数体内必须使用it参数替代对象,在run函数中可以像with函数一样可以省略,直接访问实例的公有属性和方法,另一方面它弥补了with函数传入对象判空问题,在run函数中可以像let函数一样做判空处理,适用于let,with函数任何场景。

我们这里 举一个 WebSetting 可能为空 的例子看下两个函数的表现:

// with 函数

with(webview.settings) {
      this?.javaScriptEnabled = true
      this?.databaseEnabled = true
   }
}

// run 函数

webview.settings?.run {
    javaScriptEnabled = true
    databaseEnabled = true
}

  在这种情况下,显然 run 扩展函数更好,因为我们可以在使用它之前对可空性进行检查。
  如果一段代码你需要多次使用一个对象,那么你就可以使用 with / run函数

2. let 函数 和 run 函数

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

  let函数 是一个扩展函数,默认当前这个对象作为闭包的it参数返回值是函数里面最后一行,或者指定return

  如果我们对比 T.run 和 T.let 两个函数也是非常的相似,唯一的区别在于它们接收的参数不一样。下面显示了两种功能的相同逻辑。

// run 函数
string?.run {
      println("The length of this String is $length")
}

// let 函数
string?.let {
      println("The length of this String is ${it.length}")
}

kotlin code

	  String string = "ymc";
      String var4 = "The length of this String is " + string.length();
      System.out.println(var4);
      var4 = "The length of this String is " + string.length();
      System.out.println(var4);

  如果你查看过 T.run 函数声明,你就会注意到T.run仅仅只是被当做了 block: T.() 扩展函数的调用块。因此,在其作用域内,T 可以被 this 指代。在编码过程中,在大多数情况下this是可以被省略的。因此我们上面的示例中,我们可以在println语句中直接使用 $length 而不是 ${this.lenght}. 所以我把这个称之为传递 this参数

  T.let 函数的声明,你将会注意到 T.let 是传递它自己本身到函数中block: (T)。因此这个类似于传递一个lambda表达式作为参数。它可以在函数作用域内部使用it来指代. 所以我把这个称之为传递 it参数

3. let函数 和also函数

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

   also函数 为扩展函数,默认当前这个对象作为闭包的it参数返回传入的参数自己本身

我们接下来比较下 let 和 also 的区别和相同点,

// let 函数
string?.let {
      println("The length of this String is ${it.length}")
}

// also 函数
string?.also {
      println("The length of this String is ${it.length}")
}

  然而,他们微妙的不同在于他们的返回值let返回一个不同类型的值,而also返回T类型本身,即这个。

  这两个函数对于函数的链式调用都很有用,其中let让您演变操作,而also则让您对相同的变量执行操作。

我们通过一个方法能更好的理解

// 平常的使用
fun makeDir(path: String): File  {
    val result = File(path)
    result.mkdirs()
    return result
}
// 组合使用 
fun makeDir(path: String) = path.let{ File(it) }.also{ it.mkdirs() }

从上述代码中我们可以看到 let 函数传入String ,但是返回了File对象(默认返回最后一行的表达式结果)also 则是返回File也就是 it 自身

3. apply 函数

fun  T.apply(f: T.() -> Unit): T

   apply 函数 也是一个扩展函数,在函数范围内,可以任意调用该对象的任意方法,并返回该对象

我们通过一个例子来看下 apply 的使用方法

//正常的
fun createIntent(intentData: String, intentAction: String): Intent {
    val intent = Intent()
    intent.action = intentAction
    intent.data=Uri.parse(intentData)
    return intent
}
// apply 函数
fun createIntent(intentData: String, intentAction: String) =
        Intent().apply { action = intentAction }
                .apply { data = Uri.parse(intentData) }

多种库函数在选用时候的标准(原图来源已经分不清到底是谁的了)
Kotlin 学习笔记(十一)Kotlin中的库函数: run、with、let、also和apply_第1张图片

你可能感兴趣的:(Kotlin学习笔记,Android,Kotlin学习之路)