常见高阶函数用法
基础回调
fun onItemClicked(onItemClick: (UserEntity, Int) -> Unit) {
val list = listOf(
UserEntity(100, "华晨宇", 30),
UserEntity(101, "张碧晨", 31),
UserEntity(103, "邓紫棋", 29),
UserEntity(103, "李宇春", 32)
)
onItemClick(list[0], 0)
}
fun main() {
val onItemClickListener: (UserEntity, Int) -> Unit = { item, position ->
println("item->$item,position:$position")
}
onItemClicked(onItemClickListener)
}
简化版本
fun main() {
onItemClicked { item, position ->
println("item->$item,position:$position")
}
}
item->userName:华晨宇,userId:100,age:30,position:0
拓展函数
kotlin支持对类的方法进行推展,拓展类未定义的方法,拓展本身支持自定义的或者android库中的类
class Student {
val name = "s_name"
val age = 10
}
fun Student.test() = println("name -> ${this.name} \nage -> ${this.age}")
fun main() {
val stu = Student()
stu.test()
}
name -> s_name
age -> 10
方法覆盖
kotlin支持对局部变量回调的方法实现中支持对回调方法的重定义覆盖,可以使用之前的定义的参数属性(实测也无法重新定义入参,必须使用之前的入参),只需要覆盖方法实现
fun main() {
var method = { num: Int -> println("method before $num") }
method = { println("method after $it") }
method(1)
}
结果输出.
method after 1
方法重载
kotlin支持方法参数定义默认值,也支持定义重载方法,比如自定义View我们一般要实现三个构造方法
kotlin支持方法参数定义默认值,也支持定义重载方法,比如自定义View我们一般要实现三个构造方法
public CustomView (Context context) {
this(context,null);
}
public CustomView (Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public CustomView (Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
而使用kotlin我们可以给方法定义重载的标记,下面的一个方法和上面的是等价的
class CustomView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ViewGroup(context, attrs, defStyleAttr)
泛型拓展
kotlin支持泛型的方法处理
可以看下apply和let的实现方式
public inline fun <T> T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
return this
}
public inline fun <T, R> T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
可以看出这两个方法中都有T.method()的处理,这里可以理解是泛型参数的拓展方法,和上面提到的是一致的。而这里的this指的是拓展方法所指定的泛型对象。
apply这里调用了方法后返回了this,同时泛型返回也是同泛型,也就是说是可以链式调用的,方法内可以使用this.xxx方法获取相应的属性,当然this也是可以省略的,直接也是可以的。
class A {
var a: String? = null;
var b: String? = null;
}
fun main() {
val A = A()
A.apply {
this.a = "1";
a ="1.5"; //效果是一样的
}.apply {
this.b = "2";
}
//甚至可以层层套娃玩
A.apply {
apply {
apply { ... }
}
}
}
同时apply这里的block是也是一个类拓展函数,指定的是T.()的方法,其实这个就是指定将T作为方法的this上下文进行传递,然后匿名方法体实现中就可以直接通过this获取该对象了
比如我们定义一个匿名方法使用String.(),那么下面的使用是成立的,即使我们并没有指定apply的对象
fun apply2(block: String.() -> Unit) {
}
fun main() {
apply2 {
val lenth = this.length
val str2 = this.substring(0, 3)
val charArra = this.toCharArray()
}
}
那么T.()作为匿名方法声明就可以类比上面的,就是把T作为this对象传递到匿名方法体中的。
而let则是把泛型作为it传递的,block: (T)就是传递it上下文的操作了,因为泛型都是T,block方法通过this传递了本身进去,这个就不举例了
那么把上面两个综合起来就可以看这么一个例子
fun <T, R> T.apply3(r: R, block: T.(R) -> R): R {
return block(r)
}
fun main() {
val str = "1234"
str.apply3(123) {
this.toInt() + it
//toInt() + it 等价
}.apply {
print("apply result->>>$this")
}
}
可以看出这里指定了两个泛型T和R, 然后T.(R)这里把T作为this传参,通时R作为it传参到方法体中,也就是这里可以同时使用this和it进行操作
输出结果
apply result->>>1357
那么再加一个参数呢
fun <T, R, E> T.apply4(r: R, e: E, block: T.(R, E) -> R): R {
return block(r, e)
}
fun main() {
val str = "1234"
str.apply4(123, "12") { v1, v2 ->
toInt() + v1 + v2.toInt()
}.apply {
print("apply result->>>$this")
}
}
因为it只支持本身,其实本身也是一种lambda声明,多个参数直接换成多个的格式就可以了,当然this就不用处理了,只需要处理传递进来的两参数即可
输出结果
apply result->>>1369
网友评论