Kotlin系列(十):函数进阶
- 更多分享www.catbro.cn
一、前言:
- 我们在上一篇学习了函数的定义及函数参数使用的相关知识。
-
本章我们将继续学习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、扩展函数
- 扩展函数是一个比较大的模块,会单独一篇进行讲解,需要的可以查看Kotlin 扩展函数详解
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。
-
注意事项:
- 要符合 tailrec 修饰符的要求, 函数必须在它执行的所有操作的最后一步, 递归调用它自身
- 如果递归调用后还有其他逻辑代码,不能使用尾递归
- 尾递归不能用在try/catch/finally 结构内
- 尾递归目前只能用在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表达式,这样显得代码结构更好。