精华内容
下载资源
问答
  • 主要给大家介绍了关于Kotlin中高阶函数的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • 主要介绍了Kotlin 使用高阶函数实现回调方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • 高阶函数介绍 普通函数中的参数是一种数据类型,比如列表,字符串,整型 高阶函数的实参是一个函数名,函数的返回值是一个函数。 例如在python中有一个函数是 abs 用来求整型的绝对值: 我们可以用代码表示: f = ...
  • 主要介绍了Python的高阶函数用法,结合实例形式分析了Python针对字符串、列表转换、运算、过滤等操作函数相关使用技巧与注意事项,需要的朋友可以参考下
  • C#中的高阶函数介绍

    2020-12-31 12:08:01
    高阶函数呢?听起来很好理解吧,就是函数的高阶(级)版本。它怎么高阶了呢?我们来看下它的基本定义: 1:函数自身接受一个或多个函数作为输入 2:函数自身能输出一个函数。 //函数生产函数   满足其中一个就可以...
  • 详解Python高阶函数

    2020-12-17 02:33:34
    1.什么是高阶函数 2.python中有哪些常用的高阶函数 什么是高阶函数? 在了解什么是高阶函数之前,我们来看几个小例子。我们都知道在 python 中一切皆对象,函数也不例外。比如求绝对值函数 abs,我们可以用一个变量...
  • 主要介绍了Javascript中的高阶函数介绍,本文讲解了什么是高阶函数、Javascript的高阶函数、还原高阶函数高阶函数使用实例等内容,需要的朋友可以参考下
  • kotlin提供了高阶函数这个概念,可以在一些场景提高编码效率 一、什么是高阶函数 通俗的说和数学里面的高阶函数概念类似,也就是函数里面的参数可以是函数。当然返回值也可以是函数。 二、kotlin高阶函数使用场景...
  • 主要介绍了Javascript 是你的高阶函数 ,需要的朋友可以参考下
  • 本文介绍常用高阶函数的部分:标准库函数
  • Python高阶函数—map()

    2020-12-22 03:19:26
    map()是 python 中内置的一个高阶函数,它接收一个函数 和一个可迭代对象,并通过把函数 f 依次作用在可迭代对象的每个元素上,得到一个新的迭代器(Python2则直接返回一个列表) 一个简单例子 def f(x): return x ...
  • 高阶函数指的是能接收函数作为参数的函数或类,这篇文章主要介绍了Python中常用的高阶函数,通过实例文字解释相结合给大家介绍的非常详细,需要的朋友可以参考下
  • 这篇文章主要介绍了Python3的高阶函数map,reduce,filter的示例代码,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下 函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,...
  • 高阶函数map/reduce Python内建了map()和reduce()函数。 我们先看map。map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。 举例说明...
  • 主要介绍了Vue数组响应式操作及高阶函数使用代码详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • Python functools——高阶函数 https://xercis.blog.csdn.net/article/details/106253473
  • 【kotlin】高阶函数详解

    千次阅读 2020-10-31 15:18:08
    如果一个函数接收另一个函数作为参数,或者返回值的类型是另一个函数,那么该函数就称为高阶函数 这就涉及到另一个概念了:函数类型。下面学习一下如何定义一个函数类型

    定义高阶函数

    如果一个函数接收另一个函数作为参数,或者返回值的类型是另一个函数,那么该函数就称为高阶函数

    这就涉及到另一个概念了:函数类型。下面学习一下如何定义一个函数类型,基本规则如下:

    (String,Int) -> Unit
    

    很晕吧,听我细细讲来。既然是定义一个函数类型,那么最关键的是声明该函数接收什么参数,以及它的返回值是什么。因此,左边部分就是用来声明该函数接收什么参数的,多个参数用逗号隔开,如果不接收任何参数,写一对空括号就可以了。而右边部分用于声明该函数的返回值类型,如果没有返回值就用 Unit,大致相当于 Java 中的 void

    现在将上述函数类型添加到某个函数的参数声明或者返回值声明上,那么这个函数就是一个高阶函数了,例如

    fun example(func: (String, Int) -> Unit) {
    	func("hello", 123)
    }
    

    可以看到这里的 example() 函数接收到了一个函数类型参数,因此 example() 函数就是一个高阶函数

    下面举例来说明下。这里我准备定义一个叫作 num1AndNum2() 的高阶函数,让它接收两个整形和一个函数类型的参数。我们会在 num1AndNum2() 函数中对传入的两个整型参数进行某种运算,并返回运行结果。但具体进行什么运算是由传入的函数类型参数决定的

    新建一个名为 HigherOrderFunction.kt 文件

    fun num1AndNum2(num1:Int,num2:Int,operation:(Int,Int)->Int):Int{
        val result = operation(num1,num2)
        return result
    }
    

    继续添加

    fun plus(num1: Int, num2: Int): Int {
        return num1 + num2
    }
    
    fun minus(num1: Int, num2: Int): Int {
        return num1 - num2
    }
    

    接着在这个文件写一个 main() 函数

    fun main(){
        val num1 = 100
        val num2 = 80
        val result1 = num1AndNum2(num1,num2, ::plus)
        val result2 = num1AndNum2(num1,num2,::minus)
        println("result1:"+result1)
        println("result2:"+result2)
    }
    

    运行结果
    在这里插入图片描述
    第三个参数使用了::plus::minus 的写法,这是一种函数引用方式的写法,表示将 plus() 和 minus() 函数作为参数传递给 num1AndNum2() 函数

    如果每次调用任何高阶函数时都还得先定义一个与其函数类型参数相匹配的函数,是不是太复杂了?没错,因此 Kotlin 还支持其他多种方式来调用高阶函数,比如 Lambda 表达式、匿名函数、成员引用等。其中 Lambda 表达式是最常见也是最普遍的高阶函数调用方式,刚才的代码使用 Lambda 表达式来实现(Lambda 表达式最后一行自动作为返回值),plus() 和 minus() 函数可以删掉了

    fun main() {
        val num1 = 100
        val num2 = 80
        val result1 = num1AndNum2(num1, num2) { n1, n2 ->
            n1 + n2
        }
        val result2 = num1AndNum2(num1, num2) { n1, n2 ->
            n1 - n2
        }
        println("result1:" + result1)
        println("result2:" + result2)
    }
    
    fun num1AndNum2(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int {
        val result = operation(num1, num2)
        return result
    }
    

    下面,我们回想 apply 函数,它可以用于给 Lambda 表达式提供一个指定的上下文,当需要连续调用同一个对象的多个方法时,apply 函数可以让代码变得更加精简。我们用高阶函数模仿 StringBuilder 的功能

    现在创建一个 HigherOrderFunction.kt 的文件

    fun StringBuilder.build(block:StringBuilder.()->Unit):StringBuilder{
        block()
        return this
    }
    

    这里我们给 StringBuilder 类定义了一个 build 扩展函数,这个扩展函数接收一个函数类型参数,并且返回值类型也是 StringBuilder。其中 StringBuilder. 的语法结构是什么意思呢?其实这才是定义高阶函数完整的语法规则,在函数类型前面加上 ClassName. 就表示这个函数类型是定义在哪个类当中的。这里我们把函数类型定义到 StringBuilder 类当中了,我们调用 build 函数时传入 Lambda 表达式将自动拥有 StringBuilder 的上下文

    fun main(){
        val list = listOf("Apple","Banana","Orange","Pear","Grape")
        val result = StringBuilder().build{
            append("Start eating fruit.\n")
            for(fruit in list){
                append(fruit).append("\n")
            }
            append("Ate all fruits")
        }
        println(result.toString())
    }
    

    在这里插入图片描述

    内联函数的作用

    我们一直使用的 Lambda 表达式在底层被转换成了匿名类的实现方式。这就表明,我们每调用一次 Lambda 表达式,都会创建一个新的匿名类实例,当然也会造成额外的内存和性能开销。为了解决这个问题,Kotlin 提供了内联函数的功能,它可以将使用 Lambda 表达式带来的运行时开销完全消除,只需要在定义高阶函数时加上 inline 关键字的声明即可:

    inline fun num1AndNum2(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int {
        val result = operation(num1, num2)
        return result
    }
    

    下面讨论一些更特殊的情况,比如,一个高阶函数中如果接收了两个或者更多函数类型的参数,这时我们给函数加上 inline关键字,那么 Kotlin 编译器会自动将所有引用的 Lambda 表达式全部内联。但如果只想内联其中一个 Lambda 表达式,就可以使用 noinline 关键字了

    inline fun inlineTest(block1:()->Unit,noinline block2:()->Unit){
    }
    

    刚才讲过了 inline 函数的好处了,为什么还要提供 noinline 关键字来排除内联功能呢?这是因为内联的函数类型参数在编译的时候会被进行代码替换,因此它没有真正的参数属性。非内联的函数类型参数可以自由地传递给其他任何函数,因为它就是一个真实的参数,而内联的函数类型参数只允许传递给另外一个内联函数,这也是它最大的局限性

    另外,内联函数和非内联函数还有一个重要的区别,那就是内联函数所引用的Lambda表达式中是可以使用return关键字来进行函数返回的,而非内联函数只能进行局部返回。为了说明这个问题,我们来看下面的例子

    fun main() {
      println("main start")
        val str = ""
        printString(str){s->
            println("lambda start")
            if(s.isEmpty()) return@printString
            println(s)
            println("lambda end")
        }
        println("main end")
    }
    
    fun printString(str: String, block: (String) -> Unit) {
        println("printString begain")
        block(str)
        println("printString end")
    }
    

    这里定义了一个 printString() 的高阶函数,用于在 Lambda 表达式中打印传入的字符串参数,但是如果字符串参数为空,那么就不进行打印了。Lambda 表达式中是不允许直接使用 return 关键字的,这里使用了 return@printString 的写法,表示进行局部返回,并且不再执行 Lambda 表达式的剩余部分代码

    当我们传入空字符串时:
    在这里插入图片描述
    但如果我们将 printString() 函数声明成一个内联函数,情况就不一样了:

    fun main() {
        println("main start")
        val str = ""
        printString(str){s->
            println("lambda start")
            if(s.isEmpty()) return
            println(s)
            println("lambda end")
        }
        println("main end")
    }
    
    inline fun printString(str: String, block: (String) -> Unit) {
        println("printString begain")
        block(str)
        println("printString end")
    }
    
    

    现在 printString() 函数变成了内联函数,我们可以在 Lambda表达式中使用 return 关键字了。此时的 return 代表的是返回外层的调用函数,也就是 main() 函数,重新运行程序:

    在这里插入图片描述
    将高阶函数声明成内联函数是一种良好的编程习惯,事实上,绝大多数高阶函数是可以直接声明成内联函数的,但是也有少数部分例外的情况,观察下面代码:

    inline fun runRunnable(block:() -> Unit){
        val runnable = Runnable{
            block()
        }
        runnable.run()
    }
    

    在这里插入图片描述

    首先在 runRunnable() 函数中,我们创建了一个 Runnable 对象,并在 Runnable 的 Lambda 表达式中调用了传入的函数类型参数。而 Lambda 表达式在编译的时候会被转换成匿名类的实现方式,也就是说,上述代码实际上是在匿名类中调用了传入的函数类型参数
    而内联函数所引用的 Lambda 表达式允许使用 return 关键字进行函数返回,但是由于我们实在匿名类中调用的函数类型参数,此时是不可能进行外层调用函数返回的,最多只能对匿名类中的函数进行返回,因此提示了上述错误
    如果我们在高阶函数中创建了另外的 Lambda 或者 匿名类的实现,并且在这些实现中调用函数类型参数,此时再将高阶函数声明成内联函数,就一定会提示错误

    我们可以借助 crossinline关键字可以解决这个问题

    在这里插入图片描述
    之所以会提示那个错误,就是因为内联函数的 Lambda 表达式中允许使用 return 关键字,和高阶函数的匿名类中不允许使用 return 关键字之间造成了冲突,而 crossinline关键字像一个契约,它用于保证在内联函数的 Lambda表达式中一定不会使用 return 关键字,这样冲突就不存在了

    声明了crossinline之后,我们就在无法调用 runRunnable 函数时的 Lambda表达式中使用 return 进行函数返回了,但仍可以使用 return@runRunnable 的写法进行局部返回。总体来说,除了在 return 关键字的使用上有所区别之外, crossinline保留了内联函数的其他所有特性

    高级函数的应用

    简化SharedPreferences 的用法

    首先回顾下 SharedPreferences 的用法

    val editor = getSharedPreferences("data", Context.MODE_PRIVATE).edit()
    editor.putString("name","Tom")
    editor.putInt("age",28)
    editor.putBoolean("married",false)
    editor.apply()
    

    这段代码本身已足够简单,但这种写法更多还是在用 Java 的编程思维来编写代码,而在 Kotlin 中我们明显可以做的更好,我们尝试使用高阶函数简 SharedPreferences 的用法,新建 SharedPreferences.kt 文件,然后在里面加入如下代码:

    fun SharedPreferences.open(block:SharedPreferences.Editor.() -> Unit){
        val editor = edit()
        editor.block()
        editor.apply()
    }
    

    对代码的解释:
    首先,我们通过扩展函数的方式向 SharedPreferences 类中添加了一个 open 函数,并且它还接受一个函数类型的参数,因此 open 函数自然是一个高阶函数

    由于 open 函数内拥有 SharedPreferences 的上下文,所以可直接调用 edit() 方法来获取 SharedPreferences.Editor 对象,另外 open 函数接收的是一个 SharedPreferences.Editor 的函数类型参数,因此这里需要调用 editor.block() 对函数类型参数进行调用,我们就可以在函数类型参数的具体实现中添加数据了。最后还要调用 editor.apply() 方法来提交数据,从而完成数据存储操作

    定义好 open 函数之后,使用 SharedPreferences 存储数据写法如下:

    getSharedPreferences("data",Context.MODE_PRIVATE).open {
    	putString("name", "Tom")
    	putInt("age", 28)
    	putBoolean("married", false)
    }
    

    其实 Google 提供的 KTX 扩展库中已经包含了上述 SharedPreferences 的简化用法,这个扩展库会在 AS 创建项目的时候自动引入 build.gradle 的 dependencies 中
    在这里插入图片描述
    因此我们可以直接在项目中这样写

    getSharedPreferences("data",Context.MODE_PRIVATE).edit {
    	putString("name", "Tom")
    	putInt("age", 28)
    	putBoolean("married", false)
    }
    

    简化 ContentValues 的用法

    val values = ContentValues()
    values.put("name","Game of Thrones")
    values.put("author","George Martin")
    values.put("pages",720)
    values.put("price",20.85)
    db.insert("Book",null,values)
    

    我们可以用 apply 函数进行简化,但是可以更好。首先你应该知道 Kotlin 中使用 A to B 这样的语法结构会创建一个 Pair 对象

    新建一个 ContentValues.kt 文件,然后定义一个 cvof() 方法,如下:

    fun cvOf(vararg pairs:Pair<String,Any?>):ContentValues{
    }
    

    这个方法的作用是构建一个 ContentValues 对象。cvOf()方法接收了一个 Pair 参数,也就是使用 A to B 语法结构创建出来的参数类型,但是我们在参数前加上了一个 vararg 关键字,其实 vararg 对应的就是 Java 中的可变参数列表,我们允许向这个方法传入0个,1个,2个甚至任意多个 Pair 类型的参数,这些参数都会被赋值到使用 vararg 声明的这一个变量上面,然后使用 for-in 循环可以将传入的所有参数遍历出来

    再看Pair 类型,由于 Pair 是一种键值对的数据结构,因此需要通过泛型来指定它的键和值分别对应什么类型的数据。值得庆幸的是,ContentValues 的所有键都是字符串类型的,这里可以直接将 Pair 键的泛型指定成 String。但 ContentValues 的值却可以有多种类型,所以我们需要将 Pair 值的泛型指定成 Any?。因为 Any 是 Kotlin 中所有类的共同基类,相当于 Java 中的 Object,而 Any? 则表示允许传入空值

    接下来我们开始为 cvOf() 方法实现功能逻辑,核心思路就是先创建一个 ContentValues 对象,然后便利 pairs 参数列表,取出其中的数据并填入 ContentValues 中,最终将 ContentValues 对象返回即可。存在的一个问题是:Pair 参数类型是 Any? 类型的,我们怎样让它和 ContentValues 所支持的数据类型对应起来呢?没有什么好办法,只能使用 when 语句一一判断:

    fun cvOf(vararg pairs:Pair<String,Any?>):ContentValues{
        val cv = ContentValues()
        for(pair in pairs){
            val key = pair.first
            val value = pair.second
            when(value){
                is Int -> cv.put(key,value)
                is Long -> cv.put(key,value)
                is Short -> cv.put(key,value)
                is Float -> cv.put(key,value)
                is Double -> cv.put(key,value)
                is Boolean -> cv.put(key,value)
                is String -> cv.put(key,value)
                is Byte -> cv.put(key,value)
                is ByteArray -> cv.put(key,value)
                null -> cv.putNull(key)
            }
        }
        return cv
    }
    

    这里使用了 Kotlin 的 Smart Cast 功能,比如 when 语句进入 Int 条件分支后,这个条件下面的 value 会被自动转换成 Int,而不再是 Any? 类型,这样我们就不需要像 Java 中那样在额外进行一次向下转型了,这个功能在 if 语句中也同样适用

    我们使用上面的方法:

    val values = cvOf("name" to "Game of Thrones","author" to "George Martin","pages" to 720,"price" to 20.85)
    db.insert("Book",null,values)
    

    功能性方面,cvOf() 方法好像确实用不到高阶函数的只是,但从代码实现方面,却可以结合高阶函数来进行进一步优化。比如借助 apply 函数:

    fun cvOf(vararg pairs:Pair<String,Any?>) = ContentValues().apply{
        for(pair in pairs){
            val key = pair.first
            val value = pair.second
            when(value){
                is Int -> put(key,value)
                is Long -> put(key,value)
                is Short -> put(key,value)
                is Float -> put(key,value)
                is Double -> put(key,value)
                is Boolean -> put(key,value)
                is String -> put(key,value)
                is Byte -> put(key,value)
                is ByteArray -> put(key,value)
                null -> putNull(key)
            }
        }
    }
    

    由于 apply 函数的返回值就是它的调用对象本身,因此这里我们可以使用单行代码函数的语法糖,用等号代替返回值的声明。另外,apply 函数的 Lambda 表达式中会自动拥有 ContentValues 的上下文,所以这里可以直接调用 ContentValue 的各种 put 方法

    同前,KTX 库中也提供了一个具有相同功能的 contentValuesOf() 方法:

    val values = contentValuesOf("name" to "Game of Thrones","author" to "George Martin","pages" to 720,"price" to 20.85)
    db.insert("Book",null,values)
    
    展开全文
  • Kotlin 高阶函数概念 II . Kotlin 高阶函数 作为 参数 示例解析 ( forEach 方法参数解析 ) III . 用作函数参数的 函数类型变量 ( 本示例中使用匿名函数 ) IV . 函数类型实例使用 V . Kotlin 高阶函数 整体代码示例



    I . Kotlin 高阶函数概念



    Kotlin 高阶函数 : Kotlin 的高阶函数 , 就是方法的参数 或 返回值 是函数类型的 函数 ;


    如 : List 集合的 forEach( ) 循环 , 该方法就是接收一个高阶函数类型变量作为参数 , 有点类似于 C/C++ 中的 函数指针 ( 指向函数的指针 ) ;



    II . Kotlin 高阶函数 作为 参数 示例解析 ( forEach 方法参数解析 )



    1 . 高阶函数引入 : List 集合的 forEach 方法的参数 , 就是一个高阶函数 ;


    2 . forEach () 函数原型 : forEach() 遍历集合的方法需要传入一个参数 , 下面解析这个参数 :

    /**
     * Performs the given [action] on each element.
     */
    @kotlin.internal.HidesMembers
    public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit {
        for (element in this) action(element)
    }
    

    3 . 参数类型分析 : 由上面的函数原型可以看到 , forEach ( ) 方法的参数是 action: (T) -> Unit , 参数类型是 (T) -> Unit 类型 , 参数变量名称是 action ; 这个参数类型 (T) -> Unit 类型 就是高阶函数类型 ;


    4 . forEach(action: (T) -> Unit) 参数解析 :


    ① 参数名 : action ;

    ② 参数类型 : (T) -> Unit ;

    ③ T 类型 : T 表示 forEach 遍历的集合元素类型 , 这里是 String 类型 ;


    5 . (String) -> Unit 函数类型解析 :


    ① 本质 : 是函数类型 ;

    ② 函数参数 : 其函数类型的参数是 String 字符串类型

    ③ 函数返回值 : 其函数类型的返回值类型是 Unit 类型 , 这是空返回值 相当于 Java 中的 void 类型 ;



    III . 用作函数参数的 函数类型变量 ( 本示例中使用匿名函数 )



    1 . 函数变量需求 : 在上面的 forEach ( ) 函数中 , 需要传入一个 (String) -> Unit 函数类型的变量 , 该函数类型的函数 参数是 String 类型 , 返回值是 Unit 空类型 ;


    2 . 普通的函数声明 : 下面定义的函数 , 参数类型是 String , 返回值是 Unit 空类型 , 这个函数是 (String) -> Unit 类型的 , 但是 study 不能当做参数传入到 forEach 方法中 ; list.forEach(study) , 是错误的调用 , 编译不通过 ;

    fun study(student : String) : Unit{
        println(student + " 在学习")
    }
    

    3 . 函数类型变量 : 可以使用匿名函数 , 赋值给一个变量 , 然后将这个变量当做参数传递给 forEach 当做参数 ;


    ① 指定变量 : 为 (String) -> Unit 类型函数指定一个引用变量 var study2 ;

    ② 匿名函数 : 顾名思义 , 就是没有函数名称 , 省略调上面普通函数的名称 , 赋值给变量 ; 具体用法如下 :

    var study2 = fun (student : String) : Unit{
        println(student + " 在学习")
    }
    


    IV . 函数类型实例使用



    1 . 函数类型实例使用 : 上面的 study2 就是 (String) -> Unit 函数类型的实例变量 ;

    //1 . 定义函数类型实例
    var study2 = fun (student : String) : Unit{
        println(student + " 在学习")
    }
    
    //2 . 使用函数类型实例
    
    //2.1 定义一个集合
    var students : List<String> = listOf<String>("Tom", "Jerry")
    //2.2 遍历集合
    students.forEach(study2);
    

    2 . 执行结果 :

    Tom 在学习
    Jerry 在学习
    


    V . Kotlin 高阶函数 整体代码示例



    Kotlin 高阶函数 整体代码示例 :

    package fp
    
    /*
        这里定义了一个函数 , 参数类型是 String , 返回值是 Unit 空类型
        这个函数是 (String) -> Unit 类型的
        但是不能直接将 study 传入到 forEach 方法中 , 当做参数
     */
    fun study(student : String) : Unit{
        println(student + " 在学习")
    }
    
    /*
        为 (String) -> Unit 类型函数指定一个引用变量 study2
            这个变量值 , 可以直接传递给 forEach 方法当做参数使用
    
        函数名省略 : 将一个函数赋值给一个变量 , 此时函数不能有名称 , 必须是匿名的 ;
    
        该函数可以直接通过 study2("111") 方式调用
     */
    var study2 = fun (student : String) : Unit{
        println(student + " 在学习")
    }
    
    
    fun main() {
    
        //定义一个集合
        var students : List<String> = listOf<String>("Tom", "Jerry")
    
        /*
            forEach 方法 , 接收一个函数作为参数 , 该函数的类型是指定的 , 是 (T) -> Unit 类型
                执行时 , 将集合中的元素传入 (T) -> Unit 类型函数作为参数 , 执行 (T) -> Unit 类型函数内容
    
    
            forEach 函数原型 : forEach() 遍历集合的方法需要传入一个参数 , 下面解析这个参数
                forEach(action: (T) -> Unit) 参数解析 :
                参数名 : action
                参数类型 : (T) -> Unit
                    T 表示 forEach 遍历的集合元素类型 , 这里是 String 类型
                    (String) -> Unit :
                        本质 : 是函数类型
                        函数参数 : 其函数类型的参数是 String 字符串类型
                        函数返回值 : 其函数类型的返回值类型是 Unit 类型 , 这是空返回值 相当于 Java 中的 void 类型
    
    
            Performs the given [action] on each element.
    
            @kotlin.internal.HidesMembers
            public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit {
                for (element in this) action(element)
            }
         */
        students.forEach(study2);
    }
    

    执行结果 :

    Tom 在学习
    Jerry 在学习
    
    展开全文
  • 07.常见高阶函数-sort.py
  • kotlin 高阶函数In this tutorial, we’ll be looking into kotlin higher-order functions and lambda expressions in detail. At the same time, we’ll explore function references, anonymous functions, and ...

    kotlin 高阶函数

    In this tutorial, we’ll be looking into kotlin higher-order functions and lambda expressions in detail. At the same time, we’ll explore function references, anonymous functions, and closures too.

    在本教程中,我们将详细研究kotlin高阶函数和lambda表达式。 同时,我们还将探索函数引用,匿名函数和闭包。

    Kotlin高阶函数 (Kotlin Higher-Order Functions)

    Kotlin supports functional programming. High order functions have the ability to pass a function as an argument or use it as the return value. Let’s see this through examples.

    Kotlin支持功能编程。 高阶函数可以将函数作为参数传递或将其用作返回值。 让我们通过示例来看一下。

    函数类型和引用 (Function Types and References)

    Functions in Kotlin are types.
    ()->String is a type that takes no parameters and returns a string.
    (String)->String is a type that takes a string argument and returns a string argument.

    Kotlin中的函数是类型。
    ()->String是一种不带参数且返回字符串的类型。
    (String)->String是一种接受字符串参数并返回字符串参数的类型。

    Kotlin Lambda表达式 (Kotlin Lambda Expressions)

    kotlin lambda expression

    Lambda Expressions are function literals that help us in writing a function in a short way. They provide us a compact way of writing code. Let’s define a lambda expression to see how functions act as types.


    Lambda表达式是函数文字,可以帮助我们以简短的方式编写函数。 它们为我们提供了一种紧凑的代码编写方式。 让我们定义一个lambda表达式以查看函数如何充当类型。

    fun main(args: Array<String>) {
    
        var lambdaFunction :(String)->Unit  = {s:String -> println(s)}
        lambdaFunction("Kotlin Lambda Functions")
    
        //or
        lambdaFunction =  {println(it)}
        lambdaFunction("Kotlin Lambda Functions Concise")
    
        val noArgFunction : () -> Unit ={ println("Another function")}
        noArgFunction()
    
    }
    
    //Following is printed on the console.
    //Kotlin Lambda Functions
    //Kotlin Lambda Functions Concise
    //Another function

    lambdaFunction property has a function as its type. The right-hand side is where the function is declared.

    lambdaFunction属性具有一个函数作为其类型。 右侧是函数的声明位置。

    it is used to access parameter values in the body of the lambda expression.

    it用于访问lambda表达式主体中的参数值。

    We can pass a function as a parameter inside another function too using references as shown below.

    我们也可以使用引用将函数作为参数传递给另一个函数,如下所示。

    Such functions are known as High Order Functions.

    这样的函数称为高阶函数

    fun main(args: Array<String>) {
    
        var printFunction: (String) -> Unit = { println(it) }
        functionReferencesExample("JournalDev.com", printFunction)
    
    }
    
    fun functionReferencesExample(str: String, expression: (String) -> Unit) {
        print("Welcome To Kotlin Series @")
        expression(str)
    }

    To pass a function as an argument inside another function we need to use the notation ::. Following code snippet demonstrates an example on the same.

    要将函数作为参数传递给另一个函数,我们需要使用符号:: 。 下面的代码片段在同一示例上演示了一个示例。

    fun main(args: Array<String>) {
        functionReferencesExample("JournalDev.com", ::printFunction)
    }
    
    fun functionReferencesExample(str: String, expression: (String) -> Unit) {
        print("Welcome To Kotlin Series @")
        expression(str)
    }
    
    fun printFunction(str: String) {
        println(str)
    }

    Note: We’ll look at High order functions and lambda expressions in detail in a later tutorial.

    注意 :我们将在以后的教程中详细介绍高阶函数和lambda表达式。

    高阶函数中的Lambda表达式 (Lambda Expressions inside Higher Order Functions)

    A Lambda expression can be passed inside a higher order function parameter as shown below.

    Lambda表达式可以在高阶函数参数中传递,如下所示。

    fun main(args: Array<String>) {
        printMe({ println("Lambda Inside a function")}) //prints Lambda Inside a function
    }
    
    fun printMe(string1: () -> Unit) {
        string1()
    }

    The lambda expression as a parameter runs as a function inside another function.

    lambda表达式作为参数在另一个函数中作为函数运行。

    Another example demonstrates using lambda expressions inside print function.

    另一个示例演示了在print函数内部使用lambda表达式。

    fun main(args: Array<String>) {
    println("Let's invoke a lambda function ${returnMe { "return Me " + "function"  }} here")
    }
    
    fun returnMe(string: ()->String) : String
    {
        return string()
    }
    
    //Prints
    //Let's invoke a lambda function return Me function here

    类型别名 (Type Aliases)

    Typealiases provide an alternative name for a type.
    Instead of typing the function type every time when defining a property, we can use typealias as shown below.

    Typealiases为类型提供了备用名称。
    不必在定义属性时每次都键入函数类型,而是可以使用如下所示的类型typealias

    fun main(args: Array<String>) {
        var printFunction: MyFirstAlias = { println(it) }
    }
    
    typealias MyFirstAlias =  (String)->Unit
    
    typeAlias Username = String

    This definitely enhances the readability of the code.

    这无疑提高了代码的可读性。

    异常函数 (Annoymous Functions)

    We’ve seen that lambda expressions can’t explicitly specify a return type as illustrated below.

    我们已经看到,lambda表达式无法显式指定返回类型,如下所示。

    var sum = { a: Int, b: Int -> a + b }
    var result = sum(2,3) //result is an int 5

    In order to set the return types explicitly, we can use Annoymous functions.
    An annoymous function doesn’t require a name.

    为了显式设置返回类型,我们可以使用Annoymous函数。
    异常函数不需要名称。

    fun main(args: Array<String>) {
    //Defining
    val annoSum = fun(x: Int, y: Int): Int = x + y
    //Invoking
    print(annoSum(2,3)) //5
    }

    If the parameter/return type of the annoymous function isn’t defined, it can be inferred just like normal functions.

    如果未定义匿名函数的参数/返回类型,则可以像普通函数一样进行推断。

    Let’s use Anonymous functions inside standard library high order functions.

    让我们在标准库高阶函数中使用匿名函数。

    var myList = listOf<Int>(1,2,5,7,6,10)
    
        myList = myList.filter(fun(item) = (item%2 ==0) )
        println(myList)

    filter is a higher order function that checks the given condition over each of the list items.
    In the above code, it checks for odd/even over each list integer element.

    filter是一个高阶函数,用于检查每个列表项上的给定条件。
    在上面的代码中,它检查每个列表整数元素的奇/偶数。

    Note: There are plenty of standard library functions. We’ll look at them and there use cases in a later tutorial.

    注意:有很多标准库函数。 我们将在以后的教程中研究它们以及用例。

    Kotlin封盖 (Kotlin Closures)

    Closures are functions that can access and modify properties defined outside the scope of the function.
    The following closure function is a high order function that calculates the sum of all elements of the list and updates a property defined outside the closure.

    闭包是可以访问和修改在函数范围之外定义的属性的函数。
    下面的闭包函数是一个高阶函数,它计算列表中所有元素的总和并更新在闭包外部定义的属性。

    var res = 0
    myList = listOf(1,2,3,4,5,6,7,8,9,10)
    myList.forEach { res+=it }
    println(res) //prints 55

    This brings an end to this tutorial. We’ll be looking at the standard library higher-order functions in a later tutorial. You can download the sample code of the above tutorial from the link below.

    本教程到此结束。 在后面的教程中,我们将研究标准库的高阶函数。 您可以从下面的链接下载上述教程的示例代码。

    翻译自: https://www.journaldev.com/18835/kotlin-lambda-higher-order-functions

    kotlin 高阶函数

    展开全文
  • 高阶函数 in Scala

    2015-09-20 22:12:35
    详细讲解Scala中的高阶函数部分,具体实例剖析Scala中高阶函数的意义所在,对控制抽象进行了详细的说明,参考书籍《快学Scala》、《Programming in Scala》
  • hof, C 的高阶函数.zip

    2019-09-17 23:14:52
    hof, C 的高阶函数 HigherOrderFunctions是只为函数和函数对象提供实用工具的c 11/c 14库,它可以以解决比传统元编程更简单的问题。HigherOrderFunctions是:现代:HigherOrderFunctions利用
  • java模拟js高阶函数

    2019-04-05 01:13:52
    NULL 博文链接:https://hbiao68.iteye.com/blog/1520946
  • Swift的高阶函数

    千次阅读 2019-07-24 23:04:35
    Swift的高阶函数swift常用高阶函数1. map2. flatMap3. filter4. reduce swift常用高阶函数 swift中比较常用的高阶函数有:map、flatMap、filter、reduce 1. map map可以对数组中的每一个元素做一次处理 // 计算...

    swift常用高阶函数

    swift中比较常用的高阶函数有:map、flatMap、filter、reduce
    更多swift相关教程可以参考极客学院文章

    1. map

    map可以对数组中的每一个元素做一次处理

    1. 先通过下面实例代码了解一下map的用法
    // 计算字符串的长度
    let stringArray = ["Objective-C", "Swift", "HTML", "CSS", "JavaScript"]
    func stringCount(string: String) -> Int {
        return string.characters.count
    }
    stringArray.map(stringCount)
    
    stringArray.map({string -> Int in
        return string.characters.count
    })
    
    // $0代表数组中的每一个元素
    stringArray.map{
        return $0.characters.count
    }
    
    1. 我们来查看一下map在swift中的定义
      我们看到它可以用在 Optionals 和 SequenceType 上(如:数组、词典等)。
      代码:
    public enum Optional<Wrapped> : _Reflectable, NilLiteralConvertible {
        /// If `self == nil`, returns `nil`.  Otherwise, returns `f(self!)`.
        @warn_unused_result
        public func map<U>(@noescape f: (Wrapped) throws -> U) rethrows -> U?
    }
    
    extension CollectionType {
        /// Returns an `Array` containing the results of mapping `transform`
        /// over `self`.
        ///
        /// - Complexity: O(N).
        @warn_unused_result
        public func map<T>(@noescape transform: (Self.Generator.Element) throws -> T) rethrows -> [T]
    }
    
    

    源码中的一些关键字在这里介绍一下:
    @warn_unused_result:表示如果没有检查或者使用该方法的返回值,编译器就会报警告。
    @noescape:表示transform这个闭包是非逃逸闭包,它只能在当前函数map中执行,不能脱离当前函数执行。这使得编译器可以明确的知道运行时的上下文环境(因此,在非逃逸闭包中可以不用写self),进而进行一些优化

    1. 对 Optionals进行map操作
      简要的说就是,如果这个可选值有值,那就解包,调用这个函数,之后返回一个可选值,需要注意的是,返回的可选值类型可以与原可选值类型不一致:
    ///原来类型: Int?,返回值类型:String?
    var value:Int? = 1
    var result = value.map { String("result = \($0)") }
    /// "Optional("result = 1")"
    print(result)
    
    
    var value:Int? = nil
    var result = value.map { String("result = \($0)") }
    /// "nil"
    print(result)
    
    1. 对SequenceType进行map操作

    我们可以使用map方法遍历数组中的所有元素,并对这些元素一一进行一样的操作(函数方法)。map方法返回完成操作后的数组。

    在这里插入图片描述
    我们可以对比一下用传统的For-in操作和map操作:

    1. 传统写法:
    var values = [1,3,5,7]
    var results = [Int]()
    for var value in values {
        value *= 2
        results.append(value)
    }
    //"[2, 6, 10, 14]"
    print(results)
    //传统的For-in实现起来代码很多,不简介,而且效率没有高阶函数高。
    
    2. 使用map高阶函数
    let results = values.map ({ (element) -> Int in
        return element * 2
    })
    //"[2, 6, 10, 14]"
    
    此外还有更加精简的写法:
    let results = values.map { $0 * 2 }
    //"[2, 6, 10, 14]"
    3. 
    

    通过上面的代码对比,我们可以看出高阶函数精简写法是多么的优雅,就像写诗一样。下面我们来探究一下怎么就精简这么短小了呢,连return语句都不需要了

    • 第一步
      由于闭包的函数体很短,所以我们将其改写成一行:
    let results = values.map ({ (element) -> Int in return element * 2 })
    //"[2, 6, 10, 14]"
    
    
    • 第二步
      由于我们的闭包是作为map的参数传入的,系统可以推断出其参数与返回值,因为其参数必须是(Element) -> Int类型的函数。因此,返回值类型,->及围绕在参数周围的括号都可以被忽略:
    let results = values.map ({ element  in return element * 2 })
    //"[2, 6, 10, 14]"
    
    
    • 第三步
      单行表达式闭包可以通过省略return来隐式返回闭包的结果:
      由于闭包函数体只含有element * 2这单一的表达式,该表达式返回Int类型,与我们例子中map所需的闭包的返回值类型一致(其实是泛型),所以,可以省略return。
    let results = values.map ({ element  in element * 2 })
    //"[2, 6, 10, 14]"
    
    
    • 第四步
      参数名称缩写(Shorthand Argument Names),由于Swift自动为内联闭包提供了参数缩写功能,你可以直接使用$0,$1,$2…依次获取闭包的第1,2,3…个参数。
      如果您在闭包表达式中使用参数名称缩写,您可以在闭包参数列表中省略对其的定义,并且对应参数名称缩写的类型会通过函数类型进行推断。in关键字也同样可以被省略:
    let results = values.map ({ $0 * 2 })//$0即代表闭包中的第一个参数。
    //"[2, 6, 10, 14]"
    
    
    • 第五步
      尾随闭包,由于我们的闭包是作为最后一个参数传递给map函数的,所以我们可以将闭包表达式尾随:
    let results = values.map (){ $0 * 2 }
    //"[2, 6, 10, 14]"
    

    如果函数只需要闭包表达式一个参数,当您使用尾随闭包时,您甚至可以把()省略掉:

    let results = values.map { $0 * 2 }
    //"[2, 6, 10, 14]"
    

    2. flatMap

    1. flatMap返回后的数组中不存在nil,同时它会把Optional解包
    let array = ["Apple", "Orange", "Puple", ""]
    
    let arr1 = array.map { a -> Int? in
        let length = a.characters.count
        guard length > 0 else { return nil }
        return length  
    }
    arr1 // [{some 5}, {some 6}, {some 5}, nil]
    
    let arr2 = array.flatMap { a-> Int? in
        let length = a.characters.count
        guard length > 0 else { return nil}
        return length    
    }    
    arr2 // [5, 6, 5]
    
    1. flatMap还能把数组中存有数组的数组(二维数组、N维数组)一同打开变成一个新的数组
    let array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    
    let arr1 = array.map{ $0 }
    arr1 // [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    
    let arr2 = array.flatMap{ $0 }
    arr2 // [1, 2, 3, 4, 5, 6, 7, 8, 9]
    
    1. flatMap也能把两个不同的数组合并成一个数组,这个合并的数组元素个数是前面两个数组元素个数的乘积
    let fruits = ["Apple", "Orange", "Puple"]
    let counts = [2, 3, 5]
    
    let array = counts.flatMap { count in
        fruits.map ({ fruit in
             return fruit + "  \(count)"            
        })   
    }
    array // ["Apple 2", "Orange 2", "Puple 2", "Apple 3", "Orange 3", "Puple 3", "Apple 5", "Orange 5", "Puple 5"]
    

    3. filter

    filer:过滤,可以对数组中的元素按照某种规则进行一次过滤

    // 筛选出字符串的长度小于10的字符串
    let stringArray = ["Objective-C", "Swift", "HTML", "CSS", "JavaScript"]
    func stringCountLess10(string: String) -> Bool {
        return string.characters.count < 10
    }
    stringArray.filter(stringCountLess10)
    
    stringArray.filter({string -> Bool in
        return string.characters.count < 10
    })
    
    // $0表示数组中的每一个元素
    stringArray.filter{
        return $0.characters.count < 10
    }
    

    4. reduce

    reduce:计算,可以对数组的元素进行计算

    // 将数组中的每个字符串用‘、’拼接
    let stringArray = ["Objective-C", "Swift", "HTML", "CSS", "JavaScript"]
    
    func appendString(string1: String, string2: String) -> String {
        return string1 == "" ? string2 : string1 + "、" + string2
    }
    // reduce方法中的第一个参数是初始值
    stringArray.reduce("", appendString)
    
    stringArray.reduce("", {(string1, string2) -> String in
        return string1 == "" ? string2 : string1 + "、" + string2
    })
    
    // $0表示计算后的结果, $1表示数组中的每一个元素
    stringArray.reduce("", {
        return $0 == "" ? $1 : $0 + "、" + $1
    })
    

    参考博客,教程:
    http://wiki.jikexueyuan.com/project/swift/chapter2/07_Closures.html

    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 125,561
精华内容 50,224
关键字:

高阶函数