目录

Kotlin系列(十):函数进阶


一、前言:

  • 我们在上一篇学习了函数的定义及函数参数使用的相关知识。
  • 本章我们将继续学习Kotlin函数的相关知识点。

二、函数的范围

  • 我们来看下官方给出的介绍

  • In Kotlin functions can be declared at top level in a file, meaning you do not need to create a class to hold a function, like languages such as Java, C# or Scala. In addition to top level functions, Kotlin functions can also be declared local, as member functions and extension functions.

  • 大致意思是:在Kotlin中,函数可以在一个文件的顶层声明(也就是直接在文件中声明,非类里面),这意味着你不需要像Java,C#或Scala等语言一样创建一个类来保存一个函数。 除了顶级功能之外,Kotlin功能也可以被声明为局部,作为成员函数和扩展功能。

1、局部成员函数

  • kotlin支持局部成员

  • 示例代码如下

      fun sum(a: Int, b: Int):Int {
      	fun localSum(a: Int, b: Int):Int {
      		return a + b;
      	}
      	return localSum(a,b);
      }
    

2、成员函数

  • 成员函数是指定义在类或对象之内的函数

  • 成员函数是指定义在类或对象之内的函数。

      class Sample() {
      	fun foo() { 
      		print("Foo") 
      	}
      }
    
  • 对成员函数的调用使用点号标记法。

Sample().foo() // 创建 Sample 类的实例, 并调用 foo 函数

3、扩展函数

4、尾递归函数

  • Kotlin支持一种称为尾递归(tail recursion)的函数式编程方式.

  • 这种方式是基于函数表达式和递归函数,来实现某些基本循环的的算法,采用这种方式可以有效的避免栈溢出的危险。

  • 当函数被关键字tailrec修饰,同时满足尾递归(tail recursion)的函数式编程方式的形式时,编译器就会对代码进行优化, 消除函数的递归调用, 产生一段基于循环实现的, 快速而且高效的代码。

  • 示例代码如下:

      tailrec fun plus(start: Int, end: Int, result: Int): Int = 
        if (start < end) plus(start + 1, end, start + result) else result;
    
  • 其代码等价于

      fun plus(start: Int, end: Int, result: Int): Int {
      	var res = result
      	var sta = start
    
      	while (sta < end) {
      		res += sta
      		sta++
      	}
    
      	return res
      }
    
  • 代码解析:

  • 其参数需有一个为结果值,有一个开始值加一个边界结束的值,语句后通过if语句使用参数来设定结束条件,当不符合条件的时候返回结果集。

  • 而在这里,当start<end时,我们将start+1传入函数,end传入函数,结果加上当前start传入函数,当start=>end时,返回result。

  • 注意事项:

    1. 要符合 tailrec 修饰符的要求, 函数必须在它执行的所有操作的最后一步, 递归调用它自身
    1. 如果递归调用后还有其他逻辑代码,不能使用尾递归
    1. 尾递归不能用在try/catch/finally 结构内
    1. 尾递归目前只能用在JVM环境内

三、高阶函数

  • 所谓的高阶函数,是一种特殊的函数, 它接受函数作为参数, 或者返回一个函数.

      fun sum(a: Int, b: Int, realSum: (Int, Int) -> Int): Int {
      	return realSum(a, b);
    
      }
    
      @Test
      fun test() {
      	println(sum(3, 2, { a, b -> a + b }))
      }
    
  • 执行结果为5

从上述代码,在函数sum中,realSum参数是一个函数类型:(Int, Int) -> Int,其是一个函数,接受2个Int参数,返回值是一个Int类型的值。在sum中,将传入的ab传递给realSum,将realSum的结果返回。


四、函数类型(Function Type)

  • 对于接受另一个函数作为自己参数的函数, 我们必须针对这个参数指定一个函数类型.

        fun sum(a: Int, b: Int, realSum: (Int, Int) -> Int): Int {
      	return realSum(a, b);
    
      }
    
  • 参数sumSom的类型是(Int, Int) -> Int,也就是说,它是一个函数,接受两个Int类型参数,并且返回一个Int。


五、匿名函数

  • 匿名函数看起来非常像一个常规函数声明,除了其名称省略了。其函数体 可以是表达式(如上所示)或代码块:

      fun(x: Int, y: Int): Int = x + y
    
      fun(x: Int, y: Int): Int {
      	return x + y
      }
    

六、Lambda表达式

  • Lambda是比较受欢迎的一种函数表现形式,深受开发者喜欢,但其有利有弊,减少代码的同时也增加了代码阅读难度。
  • Lambda 表达式的完整语法形式, 也就是, 函数类型的字面值, 如下: val sum = { x: Int, y: Int -> x + y }

Lambda表达式语法:

  • { 参数(参数类型可以省略) -> 函数体 }
  • 如果Lambda 表达式只有一个参数,在Kolin中可以自行判断出Lambda表达式的参数定义,此时可以省略参数的定义, 并且会为我们隐含地定义这个参数, 使用的参数名为 it:

  • 我们可以使用限定的返回语法从 lambda 显式返回一个值。否则,将隐式返回最后一个表达式的值。因此,以下两个片段是等价的:

      ints.filter {
      	val shouldFilter = it > 0 
      	shouldFilter
      }
    
      ints.filter {
      	val shouldFilter = it > 0 
      	return@filter shouldFilter
      }
    
  • 如果一个函数接受另一个函数作为它的最后一个参数, 那么Lambda表达式作为参数时, 可以写在圆括号之外.

  • 如之前的调用可以修改为:

      fun sum(a: Int, b: Int, realSum: (Int, Int) -> Int): Int {
      	return realSum(a, b);
    
      }
    
      @Test
      fun test() {
      	val result = sum(3, 2) { a, b -> a + b }
        println(result)
      }
    
  • 我们在调用sum函数时在括号外面写lambda表达式,这样显得代码结构更好。