尾递归函数
kotlin 支持函数式编程的尾递归。这个允许一些算法可以通过循环而不是递归解决问题,从而避免了栈溢出。
- 当函数被标记为
tailrec
时,编译器会优化递归,并用高效迅速的循环代替它。 - 一种特殊的递归
- 调用自身后无其他操作
- 是进行了优化的循环
tailrec fun findListNode(head: ListNode?, value: Int): ListNode?{
head?: return null
if(head.value == value) return head
return findListNode(head.next, value)
}
在递归调用代码后面是不允许有其它代码的,并且也不可以在 try/catch/finall 块中进行使用。当前的尾递归只在 JVM 的后端中可以用。
闭包
持有函数运行的状态
函数内部可以定义函数
函数内部也可以定义类
Lambda 表达式或者匿名函数,以及局部函数和对象表达式(object declarations)可以访问其 闭包 ,即在外部作用域中声明的变量。 与 Java 不同的是可以修改闭包中捕获的变量:
fun sumGTZero(c: Iterable<Int>): Int {
var sum = 0
c.filter { it > 0 }.forEach {
sum += it
}
return sum
}
val list = listOf(1, 2, 3, 4, 5)
sumGTZero(list) // 输出 15
我们再使用闭包来写一个使用Java中的Thread接口的例子:
fun closureDemo() {
Thread({
for (i in 1..10) {
println("I = $i")
Thread.sleep(1000)
}
}).start()
Thread({
for (j in 10..20) {
println("J = $j")
Thread.sleep(2000)
}
Thread.sleep(1000)
}).start()
}
一个输出:
I = 1
J = 10
I = 2
I = 3
...
J = 20
科理化
由多参函数变换为多个单个参数函数的过程。
fun log(tag: String, target: OutputStream, message: Any?){
target.write("[$tag] $message\n".toByteArray())
}
//fun log(tag: String)
// = fun(target: OutputStream)
// = fun(message: Any?)
// = target.write("[$tag] $message\n".toByteArray())
fun main(args: Array<String>) {
log("benny", System.out, "HelloWorld")
// log("benny")(System.out)("HelloWorld Again.")
::log.curried()("benny")(System.out)("HelloWorld Again.")
}
以上是两种科理化的方式。
实际上还有反科理化,了解就行。
偏函数
有时在函数传入是往往是有个值是固定的,把这个值固定,剩下的就可以称之为偏函数
fun log(tag: String, target: OutputStream, message: Any?){
target.write("[$tag] $message\n".toByteArray())
}
fun main(args: Array<String>) {
val consoleLogWithTag = (::log.curried())("main")(System.out)
consoleLogWithTag("HelloAgain Again.")
consoleLogWithTag("HelloAgain Again.")
consoleLogWithTag("HelloAgain Again.")
consoleLogWithTag("HelloAgain Again.")
}
consoleLogWithTag就可以说是log的偏函数