在搞明白Kotlin的Lambda表达式之前,需要先知道Kotlin的一个特殊函数:高阶函数。
高阶函数
在Java中,如果一个A函数想要调用B函数,可以直接调用它。如果要在调用函数A时动态设置方法B的参数,则需要在函数A中传入一个参数。
int a(int num){
return b(num) + 1;
}
int b(int num){
return 1;
}
a(10); // -> The B function is called inside the a function
但要动态设置的不是函数的参数,而是从其他地方调用的函数。例如,我调用了a中的其他函数。此函数可能是B、C或其他函数。此函数只知道一种参数类型,如int,以及一种返回值类型,如int或void
int a(??? method){
return method() + 1;
}
int b(int num){
return 1;
}
int c(int num){
return 2;
}
这种操作方式在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。
举一反三,它也可以被视为函数的返回值,我的理解是lambda本身就是一个值。值类型为void或string、int或其他类型。 ```kotlin fun lambdaValue(values:(Int) -> Unit):(Int) -> Unit{ return values } // -> Grammar sugar fun lambdaValueOne(values:(Int) -> Unit) = valueslateinit 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" } }
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" } }
完活