迹忆客 专注技术分享

当前位置:主页 > 学无止境 > 编程语言 >

Kotlin 中的高阶函数

作者:迹忆客 最近更新:2023/03/21 浏览次数:

本篇文章教授如何在 Kotlin 中使用函数将函数作为参数传递并返回函数。

Kotlin 中的函数非常灵活,它们可以存储在数据结构中、存储在变量中、作为参数传递给函数或由另一个函数返回。他们可以做非函数变量所做的一切。

Kotlin 中的高阶函数

Kotlin 中的高阶函数是返回函数或将函数作为参数或两者兼有的函数。换句话说,在 Kotlin 中,你可以有一个函数,它接受另一个函数作为参数,返回一个函数作为结果,或者两者都做,这些函数称为高阶函数。

Kotlin 中的高阶函数

让我们看一个例子来看看它是如何工作的。

fun main(){

    fun hello() {
        println("In hello!")
    }

    fun random(func : () -> Unit){
        println("In random!")
        println("calling hello")
        func()
    }

    random(::hello)
}

输出:

In random!
calling hello
In hello!

解释:

  1. 首先,我们在主函数中有另外两个函数,hellorandom

  2. hello() 不带参数并且不返回任何值(即返回 Unit)。

  3. random() 采用一个参数,即在 random 的范围内本地称为 func 的函数,并且不返回任何值。func() 函数不接受任何参数并返回一个 Unit,这意味着它不返回值。

    因此,func 是在调用 random 时作为参数传递给函数的本地名称,:(冒号)通常写在变量名称之后,以区分行为和变量名称,在 () func 函数所需的括号参数被写入,并且在 -> 之后需要函数的返回类型。

  4. 最后,我们将 hello 函数传递给 main 方法中的 random

让我们看看输出以了解程序的流程。

首先,当我们从将 hello 作为参数传递的 main 函数中调用 random 时,我们在 random 函数内部。因此,我们从随机打印的上述两行。

现在 random 称为 func,它只是 hello 函数,因为我们将它作为参数传递,因此在最后一行,它在 hello 函数中。

Kotlin 中的 Lambda 表达式

Lambda 表达式是函数文字或匿名函数,我们可以在其中以简短易读的方式编写函数。它们还使代码看起来紧凑而干净。

例如:

val sum = {num1: Int , num2: Int -> num1 + num2}

sum 采用两个 Int 变量,num1num2,并返回一个 Int num1+num2(即两个数字的和)。

在 Kotlin 中将函数作为参数传递

我们可以将一个函数作为参数传递给另一个函数。这两个函数都可以自由地具有任何返回类型,并且可以具有任意数量的数据类型参数。

此外,参数函数可以没有参数和/或没有返回值。

示例 1:

让我们看一个具有两个函数的 Employee 类的示例,years 计算两个日期之间的年差,print_details 打印员工详细信息。

import java.time.LocalDate

// Employee class
public class Employee(id: Int, name: String, joining_date: LocalDate, leaving_date: LocalDate) {
    var name: String = name
    var id: Int = id
    var joining_date: LocalDate = joining_date
    var leaving_date: LocalDate = leaving_date
}

// function years returns difference between numbers of years of joining_date and leaving_date
fun years(date1 : LocalDate, date2 :LocalDate) : Int{
    return date1.getYear()-date2.getYear()
}

// printing employee detains and years served to the company by the employee
fun print_details(emp: Employee, years: (LocalDate, LocalDate) -> Int) {
    println(
        "Employee ID: ${emp.id}\n" +
                "Employee Name: ${emp.name}\n" +
                "Years served: ${years(emp.leaving_date, emp.joining_date)}"
    )
}

// main function
fun main(args: Array<String>) {

// object of Employee class
    var Raghav = Employee(1004, "Raghav Mishra", LocalDate.parse("2005-09-30"), LocalDate.parse("2012-11-17"))

    // printing detals
    print_details(Raghav, ::years)
}

输出:

Employee ID: 1004
Employee Name: Raghav Mishra
Years served: 7
  1. Employee 类对象有四个参数:nameidjoining_dateleaving_datejoining_dateleaving_date 的数据类型为 LocalDate
  2. year 函数采用两个 LocalDate 变量。getYear() 返回特定 LocalDate 中的年份,year 函数返回两个日期中年份的差为 Int
  3. print_details 采用 Employee 类的一个对象和一个计算员工服务年限的函数。它通过将 joining_dateleaving_date 传递给 years 函数来打印 Employee IDEmployee Name 和服务年限。
  4. 在 main 方法中,我们创建了一个 Employee 类的对象,并通过传递雇员 Raghav:: years 函数来调用 print_details 函数,该函数在输出中打印详细信息。

示例 2:

为了理解和应用 Kotlin 的这个特性,让我们举一个更实际的例子来过滤列表。

fun main(args: Array<String>) {
    var nums = listOf(153, 534,773,894,247,52)
    fun odd(n : Int) : Boolean = n%2!=0
    println("Odd numbers in the list are:")
    nums.filter(::odd).forEach {n -> println(n)}
}

输出:

Odd numbers in the list are:
153
773
247

我们获取一个名为 nums 的数字列表。函数 oddInt 数作为参数,如果该数是奇数则返回 true

filter 函数将一个函数作为参数,该函数将 nums 的元素作为参数并返回一个布尔值。这里 numsInt 值的列表;因此,odd 必须将 Int 作为参数并返回一个布尔值。

odd 函数中导致 true 的所有元素都传递给(即过滤)forEach 函数。forEach() 函数将 Lambda 表达式或函数作为参数并返回一个 Unit,将每个数字打印到新行。

笔记:

nums.filter(::odd).forEach {n -> println(n)}

上面的代码也可以像下面这样编写以获得相同的结果。

nums.filter(::odd).forEach(::println)
//or
nums.filter{ odd(it) }.forEach { println(it) }
//or
nums.filter{odd(it)}.forEach(::println)

it 可以替换为其他名称,例如 Lambda 函数:nums.filter{n -> odd(n)}

因此总结一下: forEach{n -> println(n)} == forEach{println(it)} == forEach(::println)

Kotlin 函数作为返回值

高阶函数也是返回另一个函数的函数。再次返回的函数可以有一个返回值或返回一个 Unit 并且不带或不带任何数量的参数。

让我们看一个计算器的例子,我们让用户输入 2 个数字,让用户选择如何操作这些数字,最后返回结果。

我们将采用两个函数,第一个函数根据用户给出的选择返回一个函数。第二个函数取第一个函数返回的函数并运行。

// add func
fun add(a: Int, b: Int) : Int = a+b
// sub func
fun subtract(a: Int, b: Int) : Int = a-b
// multiply func
fun multiply(a: Int, b: Int) : Int {return a*b}
// division func
fun divide(a: Int, b: Int) : Int {return a/b}
// incorrect input
fun error(a: Int, b: Int) : Int {
    println("error");
    return -1
}

// choose returns a function requested by the user
fun choose(choice : Int) : (a : Int, b : Int)-> Int{
    return when(choice){
        1 -> ::add
        2 -> ::subtract
        3 -> ::multiply
        4 -> ::divide
        else -> ::error
    }
}

// function returning a function
fun perform(a : Int, b : Int, action : (a : Int, b : Int)-> Int) : Int{
    return action(a,b)
}

fun main(){
    println("Enter first number")
    var a = Integer.parseInt(readLine())
    println("Enter second number")
    var b = Integer.parseInt(readLine())
    println("Enter choice:\n1 add\n2 subtract\n3 multiply\n4 divide")
    var choice = Integer.parseInt(readLine())
    var result = perform(a,b,choose(choice))
    println("Result = $result")
}

输出:

Enter the first number
8493
Enter the second number
3
Enter choice:
1 add
2 subtract
3 multiply
4 divide
4
Result = 2831

在 main 函数中,我们先要求用户输入 2 个数字,然后再要求选择。在 choice 方法中,我们传递用户的选择。

choice 函数返回用户选择的函数。因此,我们创建了五个函数:addsubmultiplydivideerror

其中之一由 choice 函数返回。然后将该函数传递给 perform 函数,它需要两个 Int 类型的数字,以及一个由 choice 函数返回的函数,例如 func

两个用户输入的数字被传递给 funcfunc 返回的结果作为输出打印。

此外,请注意 addsub 使用 =(等于)符号初始化。multiplydivide{} 初始化。

两者都是正确的并且可以使用,但是 addsub 更容易理解。

在 Kotlin 中传递 Lambda 表达式而不是函数

在 Kotlin 中,如果我们必须只使用一次函数并且函数是单行表达式,我们可以传递 Lambda 表达式而不是函数。比如说,而不是传递 divide 函数;我们选择直接传递表达式来执行如下功能。

var res = perform(a,b, { a,b -> a/b })

转载请发邮件至 1244347461@qq.com 进行申请,经作者同意之后,转载请以链接形式注明出处

本文地址:

相关文章

在 Java 中获取文件大小

发布时间:2023/05/01 浏览次数:139 分类:Java

Java 提供了不同的方法来获取文件的字节大小。 本教程演示了在 Java 中获取文件大小的不同方法。使用 Java IO 的文件类获取文件大小 Java IO 包的 File 类提供了以字节为单位获取文件大小的功能。

Java 中的文件分隔符

发布时间:2023/05/01 浏览次数:108 分类:Java

本篇文章介绍了 Java 中的文件分隔符。Java 中的文件分隔符 文件分隔符是用来分隔目录的字符; 例如,Unix 使用 /,Windows 使用 \ 作为文件分隔符。

Java 中的文件过滤器

发布时间:2023/05/01 浏览次数:193 分类:Java

本篇文章介绍如何在 Java 中使用 FileFilter。FileFilter 用于过滤具有特定扩展名的文件。 Java内置包IO和Apache Commons IO为FileFilter提供了类和接口来进行文件过滤操作。

Java 获取 ISO 8601 格式的当前时间戳

发布时间:2023/05/01 浏览次数:132 分类:Java

本篇文章介绍了 ISO 8601 日期格式、其重要性及其在 Java 中的使用。 它还列出了一些优点来强调为什么应该使用 ISO 格式来表示日期。

在 Java 中获取数组的子集

发布时间:2023/05/01 浏览次数:142 分类:Java

本篇文章介绍了几种在 Java 中获取数组子集的方法。使用 Arrays.copyOf() 方法获取数组的子集 使用 Arrays.copyOfRange() 方法获取数组的子集

用 Java 填充二维数组

发布时间:2023/05/01 浏览次数:110 分类:Java

二维数组是基于表结构的,即行和列,填充二维数组不能通过简单的添加到数组操作来完成。 本篇文章介绍如何在 Java 中填充二维数组。

Java 中的自然排序

发布时间:2023/05/01 浏览次数:132 分类:Java

Java 中最常用的顺序是自然顺序。 本文将展示如何使用 naturalOrder() 函数对数组进行排序。

计算 Java 数组中的重复元素

发布时间:2023/05/01 浏览次数:202 分类:Java

本篇文章介绍Java计算数组中重复元素的方法。计算 Java 数组中的重复元素。我们可以创建一个程序来计算数组中的重复元素。 该数组可以是未排序的,也可以是已排序的。

Java 中 List 和 Arraylist 的区别

发布时间:2023/05/01 浏览次数:90 分类:Java

表示为单个单元的一组单个对象称为集合。 在 Java 中,Collection 是一个具有多个已定义接口和类的框架,用于将一组对象表示为一个单元。 它允许我们操纵

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

最新推荐

教程更新

热门标签

扫码一下
查看教程更方便