首先要理解什么是纯函数:
在函数的调用过程中,没有任何的全局状态被修改。
举个不那么恰当的例子:
object functionalPrograming {
// 定义一个全局变量
var list: List[Double] = Nil
// 主方法中分别调用两种类型的函数
def main(args: Array[String]): Unit = {
println(sin(1.0))
println(list)
println("----------")
println(sinList(1.0))
println(list)
}
// 定义一个纯函数
def sin(x: Double): Double = {
scala.math.sin(x)
}
// 定义一个非纯函数
def sinList(x: Double): Double = {
list = list :+ scala.math.sin(x)
scala.math.sin(x)
}
}
===> 0.8414709848078965
===> List()
===> ----------
===> 0.8414709848078965
===> List(0.8414709848078965)
可以看到,同样实现返回 sin(x) 功能的函数,代码中定义的 sin 方法没有任何的全局状态被修改;而定义的 sinList 方法中,每次调用都向全局变量 list 中添加一次计算结果。
在实际的开发过程中,纯函数极大的简化了函数的分析、测试和调试。我们可以不用考虑该函数的上下文信息。
而且由于没有任何全局的对象被修改,对函数的并发调用也是安全可靠的,不需要任何线程安全的编写技巧。多线程程序的大部分
考虑另外一种情况:
object functionalPrograming02 {
// 主方法
def main(args: Array[String]): Unit = {
// 定义一个变量,作为 sinAnd 函数的因子
var factor: Int = 2
// 定义 sinAnd 函数
val sinAnd: Double => Double = (x: Double) => scala.math.sin(x) * factor
println(sinAnd(1))
println("-----------------")
factor = 3
println(sinAnd(1))
}
}
===> 1.682941969615793
===> -----------------
===> 2.5244129544236893
可以看到,尽管 sinAnd 是一个不可变的函数字面量,当 factor 改变时,sinAnd 的行为也跟着改变。
然而 factor 并不是 sinAnd 的参数,而是一个自由变量,是一个当前作用域中某个值的引用。所以编译器创建了一个闭包,用于包含 sinAnd 与它引用的外部变量的上下文信息,从而也就绑定了外部变量本身。
一般来说 sinAnd 也叫纯函数。
请注意区别调用函数引发外部变量改变,和改变外部变量影响函数结果的差异。
ps:
我们可以将后者写成方法
object SinAnd {
var factor = 2
def sinAnd(x: Int) = scala.math.sin(X) * factor
}
SinAnd.sinAnd(1)
===> 1.682941969615793
SinAnd.factor = 3
SinAnd.sinAnd(1)
===> 2.5244129544236893
未完
因篇幅问题不能全部显示,请点此查看更多更全内容