1. 实现:为什么会导致空指针异常
val factorial: Int => Int = {
println(s"Before recursive def: $factorial")
almostFactorial(factorial)
}
运行此代码会显示在递归定义中factorial
is null
。答案在于将 Scala Function 值实现为 JVM 中的对象。
由于对象的默认值为 null 并且阶乘在分配给时尚未初始化val factorial : Int => Int
is null
.
当对象被创建时val
s 立即被评估。所以编译器会回退到默认值。
2. 实施:为什么有效
通过使用fun _
语法将函数的实现更改为partial applied function
。当您提供 Int 时将对其进行评估。因此,不会在评估 val 的同时评估它。
因此,该函数将通过调用 main 方法来评估。当 on 运行程序时将调用它。
因此,添加一些打印语句(不好的风格,不要在生产代码中这样做)将帮助您在对象创建时找出 vals 的值:
val factorial: Int => Int = {
println(s"Before recursive def: $factorial")
val partialFactorial = factorial(_)
println(partialFactorial)
almostFactorial(partialFactorial)
}
运行第二个实现,您将得到以下输出
Before recursive def: null
<function1> <- Partial applied factorial(_)
120
扩展示例:为什么使用部分应用功能不会自动保护您
所以函数是null
在对象创建时。如果您在 val 的实现中直接向部分应用函数提供值,如下例所示:
val factorial: Int => Int = {
println(s"Before recursive def: $factorial")
val partialFactorial = factorial(_)
println(partialFactorial)
println(partialFactorial(2)) // here we will again cause a null pointer exception
almostFactorial(partialFactorial)
}
你最终会再次遇到空指针异常:
$scala Factorial
Before recursive def: null
<function1>
java.lang.NullPointerException
at Factorial$$anonfun$1.apply$mcII$sp(Example.scala:5)s