Kotlin笔记(附加)
函数式编程
命令式编程,其实就是最常见的编程方式:在编程的时候,我们需要告诉计算机每一步具体都要干什么。
1 | fun foo(): List<Int> { |
函数式,或者说“声明式”的代码
1 | fun fp() = listOf(1, 2, 3, 4).filter { it % 2 == 0 } |
区别:
- 它只需要声明我们想要什么,而不必关心底层如何实现。
- 代码更加简洁,可读性更高。
3.0 版本的词频统计程序,其实并没有完全发挥出 Kotlin 函数式编程的优势,因为其中的“getWordCount()”“mapToList()”都是我们自己实现的。事实上,我们完全可以借助 Kotlin 标准库函数来实现。
1 | fun processText(text: String): List<WordFreq> { |
到底什么是函数式编程?
函数是一等公民
- 函数可以独立于类之外,这就是 Kotlin 的顶层函数;
- 函数可以作为参数和返回值,这就是高阶函数和 Lambda;
- 函数可以像变量一样,这就是函数的引用;
- 当函数的功能更加强大以后,我们就可以几乎可以做到:只使用函数来解决所有编程的问题。
纯函数
- 函数不应该有副作用。所谓副作用,就是“对函数作用域以外的数据进行修改”,而这就引出了函数式的不变性。在函数式编程当中,我们不应该修改任何变量,当我们需要修改变量的时候,我们要创建一份新的拷贝再做修改,然后再使用它(这里,你是不是马上就想到了数据类的 copy 方法呢?)。
- 无副作用的函数,它具有幂等性,换句话说就是:函数调用一次和调用 N 次,它们的效果是等价的。
- 无副作用的函数,它具有引用透明的特性。
- 无副作用的函数,它具有无状态的特性。
实战:函数式的循环
for 循环,是命令式编程当中最典型的语句
1 | fun loop(): Int { |
仅仅只使用函数,我们该如何实现这样的功能呢?答案其实很简单,那就是递归。
1 | fun recursionLoop(): Int { |
我们知道,递归都是有调用栈开销的,所以我们应该尽量使用尾递归。对于这种类型的递归,在经过栈复用优化以后,它的开销就可以忽略不计了,我们可以认为它的空间复杂度是 O(1)。
1 | fun recursionLoop(): Int { |
在实际的开发工作中,这种方式是不推荐的,毕竟它太绕了,对吧?如果要在工作中实现类似的需求,我们使用 Kotlin 集合操作符一行代码就能搞定:
1 | fun reduce() = (1..10).reduce { acc, i -> acc + i } // 结果 55 |
Kotlin 还为我们提供了另一个更简单的操作符,也就是 sum:
1 | fun sum() = (1..10).sum() // 结果 55 |
表达式思维
不变性思维
空安全思维
关注我
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 droidYu!