美文网首页
七,Kotlin常见高阶函数用法

七,Kotlin常见高阶函数用法

作者: CarlosLynn | 来源:发表于2021-02-09 00:55 被阅读0次

常见高阶函数用法

基础回调

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

相关文章

网友评论

      本文标题:七,Kotlin常见高阶函数用法

      本文链接:https://www.haomeiwen.com/subject/derqxltx.html