在搞明白Kotlin的Lambda表达式之前,需要先知道Kotlin的一个特殊函数高阶函数

高阶函数

  • 在Java中,如果一个A函数想要调用B函数,可以直接调用它。如果要在调用函数A时动态设置方法B的参数,则需要在函数A中传入一个参数。

    1. int a(int num){
    2. return b(num) + 1;
    3. }
    4. int b(int num){
    5. return 1;
    6. }
    7. a(10); // -> The B function is called inside the a function
  • 但要动态设置的不是函数的参数,而是从其他地方调用的函数。例如,我调用了a中的其他函数。此函数可能是B、C或其他函数。此函数只知道一种参数类型,如int,以及一种返回值类型,如int或void

    1. int a(??? method){
    2. return method() + 1;
    3. }
    4. int b(int num){
    5. return 1;
    6. }
    7. int c(int num){
    8. return 2;
    9. }

    这种操作方式在Java中是不被允许的。

  • 但是,在执行函数时,我想选择调用哪个方法。我希望它可以动态设置。换句话说,我想把一个函数作为参数传递给另一个函数,传递给另一个方法。这可以实现吗?可能不会!但是,它也可以实现! ```java int a(Wrapper wrapper){ return wrapper.method(); }

interface Wrapper{ int method(); }

Wrapper wrapper = new Wrapper() { @Override public int method() { return 0; } }; void performA(){ a(wrapper); }

    **我们可以使用接口包装函数,然后将接口类型传递给函数的参数类型。调用方法时,我们将接口的对象作为参数传递。如果您不理解,请举另一个例子:**

- **View.OnClickListener()**

```java
View.OnClickListener onClickListener = new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        doSomething();
    }
};
button.setOnClickListener(onClickListener);
**这里,传递Onclicklistener类型,它本质上传递一个可以稍后调用的函数:onClick()。因为Java不允许传递方法,所以我们将其包装在要传递的对象中。在kotlin中,函数参数也可以是函数类型!当函数具有函数类型的参数时,如果调用它,则必须传递函数类型的对象,这样的函数称为“高阶函数”。什么是函数类型对象?是的,这就是一个lambda表达式。**

Lambda表达式

  • Lambda表达式本质上是一个对象,返回值可以作为常规对象处理。例如,string、int、float、livedata等。这里需要强调的是,lambda表达式默认返回最后一行代码的执行结果,不能使用return。
    lateinit var valueOne:() -> Unit   // -> Object of function type with no function parameter and return value of void
    lateinit var valueTwo:(String,Int) -> String  // -> There are two parameters. The parameter types are string and int function objects
    ....
    fun performValueOne(){
      valueOne = {
          Log.e("performValueOne", "valueOne has been initialized")
      }
      valueOne()  // Log: valueOne has been initialized
    }
    fun performValueTwo(){
      valueTwo = { paramsOne:String,paramsTwo:Int ->
          "performValueTwo has been initialized"
      }
    }
    
    举一反三,它也可以被视为函数的返回值,我的理解是lambda本身就是一个值。值类型为void或string、int或其他类型。 ```kotlin fun lambdaValue(values:(Int) -> Unit):(Int) -> Unit{ return values } // -> Grammar sugar fun lambdaValueOne(values:(Int) -> Unit) = values

fun lambdaValueTwo(values:(Int) -> Unit):(Int) -> Unit{ values(10) // However, when executed here, the following performlambdavaluetwo function will print the number 10 passed in the past return values }

fun performLambdaValueTwo(){
lambdaValueTwo({ values:Int ->
Log.e(TAG, “$values”)
})
} // If the parameter of the higher-order function is the last one, it can be written directly outside the parentheses. If there is only one parameter, “()” can be omitted directly and “{}” can be used directly fun performLambdaValueTwo(){
lambdaValueTwo{values:Int -> Log.e(TAG, “$values”) } }

    **此外,lambda除了作为函数的参数和返回值类型外,还可以指定给变量。但是,对于普通函数,必须添加“::”。**
```kotlin
fun a(funParam:(Int) -> String):String{
    return funParam(10)
}
fun b(params:Int):String{
    return params.toString()
}
fun perform(){
    val d = ::b
    a(d) 
}
**为什么要添加“::”?官方文件称这称为“Function Reference”。这是什么意思?**

回想一下,lambda本质上是一个对象。添加“::”表示存在将函数转换为对象的情况。因为只有对象可以作为参数传递,而为变量赋值也是如此。只能将对象指定给变量。然而,kotlin函数的性质决定了它不能被视为对象。我们该怎么办?Kotlin的选择是创建一个与函数具有相同功能的对象。是使用“::”。

在kotlin中,函数添加了“::”,它将不表示函数本身,而是表示对象或对对象的引用。但是这个对象不是函数本身,而是一个与这个函数具有相同函数的对象。在使用函数时使用此对象。

fun b(params:Int):String{
    return params.toString()
}
fun perform(){
    val d = ::b
    d(1)
    d.invoke(1)
    (::b)(1)
    (::b).invoke(1)
}
**再次强调,在使用“::”之后:“它将不是一个函数,而是一个对象,一个函数类型的对象。无法使用“()”调用对象,而函数类型的对象可以。但是真正调用的是这个对象的invoke()函数。**
  • Example

    val a = {x:Int,y:String ->
      Log.e("", "Nice to meet you")
      10
    }
    Log.e("", "${a(10,"Shiki")}")  
    // ->
    // Nice to meet you
    // 10
    
  • RecyclerView的Item点击事件

    class Adapters(private val itemClick:(String) -> Unit):ListAdapter<String,Adapters.ViewHolder>(
     object : DiffUtil.ItemCallback<String>() {
         override fun areItemsTheSame(oldItem: String, newItem: String) = oldItem === newItem
         @SuppressLint("DiffUtilEquals")
         override fun areContentsTheSame(oldItem: String, newItem: String) = oldItem == newItem
     }
    ){
     inner class ViewHolder(binding: HomeBannerItemBinding):RecyclerView.ViewHolder(binding.root){
         val text = binding.text
         fun bind(str:String){
    
         }
     }
    
     override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
         HomeBannerItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)).apply { 
             text.setOnClickListener { 
                 itemClick(getItem(absoluteAdapterPosition))
             }
     }
    
     override fun onBindViewHolder(holder: ViewHolder, position: Int) {
         holder.bind(getItem(position))
     }
    }
    
    class HomeFragment : Fragment(R.layout.fragment_home) {
     private val binding: ViewBinding by bindView()
     private val rvAdapter = HomeRvAdapter()
     private val adapter = Adapters{ str:String ->
    
     }
    
     companion object {
         const val TAG = "HomeFragment"
     }
    }
    

    完活