kotlin 回调函数、let、also、run 、with、apply 使用总结

460 阅读3分钟

kotlin lambda 简化

————————kotlin 回调函数、let、also、run 、with、apply 使用总结

Lambda 表达式(lambda expression)是一个匿名函数。编程中提到的 lambda 表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数。

  • 回调函数
  • 内联函数 let
  • 内联函数 also
  • 内联函数 with
  • 内联函数 run
  • 内联函数 apply
  • 用法总结

一、回调函数

  • 回调函数的Java写法
mEditText.addTextChangedListener(new TextWatcher() {
    @Override
    public void afterTextChanged(Editable editable) {
	   // TODO
    }
});
  • 回调函数的kotlin写法
mEditText?.addTextChangedListener(object : TextWatcher {
    override fun afterTextChanged(editable: Editable) {
	   // TODO
	}
})
  • 在Kotlin中,对于接口只有一个回调的方法,符合使用lambda
mEditText.addTextChangedListener({
   editable: Editable ->
   // TODO
})

// 如果以上代码中没有回调参数的话,可以直接把editable去掉
mEditText.addTextChangedListener({
   // TODO
})

// addTextChangedListener 函数最后一个参数是一个函数,可以直接把括号的实现提到圆括号外面
mEditText.addTextChangedListener(){
   // TODO
}

//  addTextChangedListener函数只有一个参数,可以直接省略圆括号
mEditText.addTextChangedListener{
   // TODO
}

二、内联函数 let

表示object不为null的条件下,才会去执行let函数体

// 表示object不为null的条件下,才会去执行let函数体
mEditText = findViewById<EditText>(R.id.search_et);
mEditText?.let {
    // it.todo()
    it.setSelection(0)
}

三、内联函数 also

从结构上看alsolet比较像。不同点是它们各自返回的值不一样,let函数是以闭包形式返回最后一行代码的值,如果最后一行为空就返回一个Unit类型的默认值;also函数的返回的是传入对象本身。

// 表示object不为null的条件下,才会去执行let函数体
mEditText = findViewById<EditText>(R.id.search_et).also {
    // it.todo()
    it.setSelection(0)
}

四、内联函数 with

适用于调用同一个类的多个方法时,可以省去类名重复,直接调用类的方法即可

  • with 一般结构
with(object){
  //todo
}
  • with 简化过程
// with函数最原始样子如下:
val result = with(user, {
       println("my name is $name, I am $age years old, my phone number is $phoneNum")
       1000
})
// 由于with函数最后一个参数是一个函数,可以把函数提到圆括号的外部,所以最终with函数的调用形式如下:
val result = with(user) {
       println("my name is $name, I am $age years old, my phone number is $phoneNum")
       1000
}
  • with 使用场景 适用于调用同一个类的多个方法时,可以省去类名重复,直接调用类的方法即可
// java 写法
@Override
public void onBindViewHolder(ViewHolder holder, int position) {

    ItemBean item = getItem(position);
	if (item == null) {
		return;
	}
	holder.mTitleTv.setText(item.title);
	holder.mSubTitleTv.setText(item.subTitle);
	holder.mDescTv.setText(item.desc);
}

// kotlin 写法
override fun onBindViewHolder(holder: ViewHolder, position: Int){
   val item = getItem(position)?: return
   //
   with(item){
      holder.mTitleTv.text = title
	  holder.mSubTitleTv.text = subTitle
	  holder.mDescTv.text = desc
   }
}

五、内联函数 run

  • run 适用场景 适用于let、with函数任何场景。 run函数是let、with两个函数结合体,它弥补了let函数在函数体内必须使用it参数替代对象,在run函数中可以像with函数一样,直接访问实例的公有属性和方法; 另一方面它弥补了with函数传入对象判空问题,在run函数中可以像let函数一样做判空处理;
//  借助上边案例的代码:内联函数 with
override fun onBindViewHolder(holder: ViewHolder, position: Int){
   val item = getItem(position)?: return
   //
   with(item){
      holder.mTitleTv.text = title
	  holder.mSubTitleTv.text = subTitle
	  holder.mDescTv.text = desc
   }
}

// 内联函数 run
override fun onBindViewHolder(holder: ViewHolder, position: Int){
      val item = getItem(position)?: return
	  item?.run{
      		holder.mTitleTv.text = title
	  		holder.mSubTitleTv.text = subTitle
	  		holder.mDescTv.text = desc
			}
}

六、内联函数 apply

从结构上看applyrun比较像。不同点是它们各自返回的值不一样,run函数是以闭包形式返回最后一行代码的值;apply函数的返回的是传入对象本身。 因此apply函数 一般用于一个对象实例初始化的时候,需要对对象中的属性进行赋值;或者动态inflate出一个XML的View的时候需要给View绑定数据也会用到;

// 一个对象实例初始化的时候,需要对对象中的属性进行赋值
mEditText = findViewById<EditText>(R.id.search_et).apply { 
    // 点击事件
    setOnClickListener{
	// TODO 
    }
}

用法总结

  • let、also 用于替代判空
  • run 、with 用于绑定数据
  • apply 用于对象初始化

========== THE END ==========

wx_gzh.jpg