Kotlin作用域函数

Kotlin常用的run、let、apply、also、with等统称为作用域函数:

作用域函数作用域对象返回值
runthis任意值
letit任意值
applythis调用者
alsoit调用者

上表整理了各个函数的对比,还有一个with,可以理解为参数版本的run。
接下来具体介绍一下各函数的使用:

1.let


定义

public inline fun <T, R> T.let(f: (T) -> R): R = f(this)

使用场景

当receiver为nullable类型时,使用let配合?.可以简化判空操作;特别是当对某个nullable对象有连续操作时更加方便

val member : User?
...
//不使用?.
var name = ""
var age = ""
if (member != null) {
	name = member.name.toUpperCase()
	age = member.age.toUpperCase()
}
val id = name + age

//使用?.
val name = member?.name?.toUpperCase() ?: ""
val age = member?.name?.toUpperCase() ?: ""
val id = name + age

//使用let + ?.
val id = member?.let{
	it.name.toUpperCase() + it.age.toUpperCase()
} ?: ""

2.run


定义

public inline fun <T, R> T.run(f: T.() -> R): R = f()

使用场景

run与let都用来完成一段计算你并返回任意值,区别仅在于block内是it(let)还是用this(run),那么如何区分两者的使用场景呢?

  • 当receiver不是自身对象时(需要调用对象的公有成员或方法),使用let
  • 当receiver是自身对象时(需要调用私有成员或方法),使用run
//run
class View {
	fun doSth() {
		...
		val width = run {
			if( !isShown ) 	0
			else childView.map{it.width}.sum()
		}
		...
	}
}

//let
class Util {
	fun doSth() {
		...
		val width = view.let {
			if (!it.isShown) = 0
			else it.childView.map{it.width}.sum()
		}
		...
	}
}

3.apply


定义

public inline fun <T> T.apply(f: T.() -> Unit): T { f(); return this }

使用场景

apply常用用更新receiver自身属性

//不使用apply
class MyFragment: Fragment() {
  companion object {
    fun new(foo: Int, bar: Int): MyFragment {
      val args = Bundle()
      args.putInt("foo", foo)
      args.putInt("bar", bar)
      val myFragment = MyFragment()
      myFragment.arguments = args
      return myFragment
    }
  }
}

//使用apply
class MyFragment: Fragment() {
  companion object {
    fun new(foo: Int, bar: Int): MyFragment =
      MyFragment().apply {
        arguments = Bundle().apply {
          putInt("foo", foo)
          putInt("bar", bar)
        }
      }
  }
}

4.also


also是1.1之后追加的作用域函数

定义

public inline fun <T> T.also(block: (T) -> Unit): T { block(this); return this }

使用场景

also和apply的block对返回自身,区别在于it引用(also)还是this引用(apply)

  • apply主要用于更新自身
  • also常用于完成一个自身以外的副作用,不会更改返回值
class MyFragment: Fragment() {
  companion object {
    fun new(foo: Int, bar: Int): MyFragment =
      MyFragment().apply {
        arguments = Bundle().apply {
          putInt("foo", foo)
          putInt("bar", bar)
        }
      }.also {
      	Log.d(TAG, "${it.javaClass.name} created!")
      }
  }
}

5.with


定义

public inline fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()

使用场景

如前所属,with相当于参数版本的run,几乎可以由run替代。而且由于with不能配合?.使用,相对上面几个的使用频率较低,以我手头的一个Android项目为例,7000行代码中没有使用到with

函数使用次数
let54
with0
run40
apply37
also12

何为作用域?

作用域函数的作用域到底是什么意思呢?scope functions 一词最早来自于官方blog
What’s new in Standard Library M13 and M14
引用如下:

Prior to M13 there were two so-called scope functions in the Standard
Library: let and with. We call them scope functions, because their
only purpose is to modify scope of a function passed as the last
parameter.

作用域函数的主要目的是改变block的作用域,也就是改变block的receiver或者parameters。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fundroid

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值