Kotlin高阶函数探究

如果一个函数接收另一个函数作为参数,或者返回类型是一个函数,那么这个函数我们就称之为高阶函数。任何以lambda或者函数引用作为参数的函数,或者返回值为lambda或函数引用的函数,都是高阶函数。

在参数中使用高阶函数示例:
/**
     * 加法
     */
    fun add(a: Int, b: Int): Int {
        return a + b
    }

    /**
     * 减法
     */
    fun minus(a: Int, b: Int): Int {
        return a - b
    }

    /**
     * 乘法
     */
    fun cheng(a: Int, b: Int): Int {
        return a * b
    }

/**
 * 运算
 *
 * operate:(Int, Int)->Int 表示定义的一个函数,将其作为calculate参数的形参,实际传的时候是传入add或minus函数
 */
fun calculate(a: Int, b: Int, operateType: (Int,Int) -> Int): Int {
        return operateType(a, b)
}

测试:

        Log.i("minfo", "" + calculate(12, 4, ::add))
        Log.i("minfo", "" + calculate(12, 4, ::minus))
        Log.i("minfo", "" + calculate(12, 4, ::cheng))

然后将add方法的变相写法:

/**
     * 将函数作为变量
     */
    val add1 = fun(a: Int, b: Int): Int {
        return a + b
    }
  
    //直接返回结果
    val add2 = fun(a: Int, b: Int) =  a + b

    //函数闭包写法
    val add3 = {a: Int, b: Int->
        a + b
    }

    val add4 = ::add
高阶函数作为返回值示例
//此方法的作用是如果type等于1,那么就从Num类中取出num进行乘法操作,如果不等于一,就进行相加操作
    fun getNum(type: Int): (Num) -> Int {
        if (type == 1) {
          //这是一种写法
            return { entity ->
                entity.num * entity.num
            }
        } else {
         //这是另一种简写,可以用it代替entity参数
            return {
                it.num + it.num
            }
        }
    }

首先定义了一个高阶函数,他传入三个参数,两个Int型的值和一个函数类型的值,在方法内部调用“函数类型的值”,因为它本身是函数,所以可以直接调用,并且将前两个Int型作为形参传了进去。接下来我们定义了两个函数add和minus,这两个函数实现他们本身的逻辑,最后在main函数里面调用了此高阶函数,其中::add和::minus是固定写法,表示函数的引用。

自己实现kolin自带高阶函数:

inline fun <T> Iterable<T>.myFilter(predicate:(T) -> Boolean): List<T> {
    var list = ArrayList<T>()

    for (item in this) {
        if (predicate(item)) {
            list.add(item)
        }
    }

    return list
}

inline fun <T> Iterable<T>.myForEach(handle:(T) -> Unit) {
    for (item in this) {
        handle(item)
    }
}

inline fun <T> T.myApply(handle:(T)-> Unit): T {
    handle(this)
    return this
}

inline fun <T, R> myWith(t: T, use:(T)-> R): R {
    return use(t)
}

inline fun <T, R> T.myRun(handle:(T) -> R): R {
    return handle(this)
}

测试使用:

ArrayList<User>().myApply {
            add(User("小王", 15))
            add(User("小李", 22))
            add(User("小张", 25))
        }.myFilter({
             it.age > 20
         }).myForEach({
             Log.i("minfo", it.name)
         })

        myWith(User("小王", 15)) {
            name = "哈哈"
            Log.i("minfo", name)
        }

        User("小王", 15).myRun {
            name = "修改小王为小花"
            Log.i("minfo", name)
        }

参考
Kotlin高阶函数

lambda(高阶函数)转成Java是怎么样的

将如下高阶函数转成java

    fun calculate(a: Int, b: Int, operateType: (Int,Int) -> Int): Int {
        return operateType(a, b)
    }

转如下代码:

   public final int calculate(int a, int b, @NotNull Function2 operateType) {
      Intrinsics.checkNotNullParameter(operateType, "operateType");
      return ((Number)operateType.invoke(a, b)).intValue();
   }

java中,则将高阶函数用了kotlin中一个接口Funtions来代替,接口仅有一个invoke方法,接口方法兼容了不同数量参数的高阶函数。

package kotlin.jvm.functions

/** A function that takes 0 arguments. */
public interface Function0<out R> : Function<R> {
    /** Invokes the function. */
    public operator fun invoke(): R
}
/** A function that takes 1 argument. */
public interface Function1<in P1, out R> : Function<R> {
    /** Invokes the function with the specified argument. */
    public operator fun invoke(p1: P1): R
}
/** A function that takes 2 arguments. */
public interface Function2<in P1, in P2, out R> : Function<R> {
    /** Invokes the function with the specified arguments. */
    public operator fun invoke(p1: P1, p2: P2): R
}
...

高阶函数有几个参数,就使用对应几个参数的那个接口替换,并在java代码中调用invoke方法。

java调用kotlin的高阶函数是怎么调的

在java中调用如下高阶函数

    fun calculate(a: Int, b: Int, operateType: (Int,Int) -> Int): Int {
        return operateType(a, b)
    }

可以知道转为java之后函数参数变为了Functions类里面接口的类型,

   public final int calculate(int a, int b, @NotNull Function2 operateType) {
      Intrinsics.checkNotNullParameter(operateType, "operateType");
      return ((Number)operateType.invoke(a, b)).intValue();
   }

具体调用时,java调用需要传入Function接口类型参数,如这里是2个参数,传入Function2对象,需要自行实现invoke回调方法。如果该高阶函数只有一个参数,则这里是new Function1()

new LambdaUse().calculate(1, 2, new Function2<Integer, Integer, Integer>() {
            @Override
            public Integer invoke(Integer integer, Integer integer2) {
                return null;
            }
        });
我理解的使用高阶函数的场景

在以前java里面需要将不确定的功能暴露给外部或者子类实现,可以使用接口或者抽象方法来调用,将实现交给外部。那么这个高阶函数就是实现同样功能的写法,用接口或者抽象方法来实现的地方,都可以改成高阶函数来做。

封装网络请求的例子就是一个很好的事例,如果不使用高阶函数,那么我们为了实现网络请求成功后的回调,还得额外多写一些接口类,得益于高阶函数,我们只需要这样即可:

    /**
     * 传入suspend方法发起请求,获取到BaseData数据,如果请求成功回调successCallBack函数并返回 T
     * 如果失败,调用failCallBack函数自行实现处理
     */
    fun <T: Any> requestData(
        showLoading: Boolean = true,
        request: suspend () -> BaseData<T>,
        successCallBack: (T) -> Unit,
        failCallBack: suspend (String) -> Unit = { errMsg->
            showLoading()
        }
    ) {
        viewModelScope.launch {
            if (showLoading) {
                showLoading()
            }
            try {
                val baseData = request.invoke()
                if (baseData.isSuccess()) {
                    baseData.data?.let { successCallBack(it) }
                } else {
                    baseData.errorMsg?.let { error(it) }
                }
            } catch (e: Exception) {
                e.message?.let { failCallBack(it) }
            } finally {
                if (showLoading) {
                    showLoading()
                }
            }
        }
    }

调用请求处理:

    fun loadData() {
        requestData(
            showLoading = true,
            request = { getUser() },
            successCallBack = { data ->
        
            })
    }

    suspend fun getUser(): BaseData<User> {
        return TODO("Provide the return value")
    }
Demo地址:

https://github.com/running-libo/HigherOrderFunction

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容