如果编译器在这种情况下没有推断包装,我不明白在scala中有一个可选类型的意义:
f(null) // WHY ISN"T THE COMPILER DOING ANYTHING HERE!
def f(x : Option[String]) = {
// WHY DOES IT CRASH WHEN MATCHING "SOME(NULL)" !!
val = x match {
case Some(x) => s"blah blah append $x"
case None => "" // !!! BOOM CRASH null scala.MatchError: null
at
}
...
...
}
如果我现在仍然需要在f
函数中检查null,我会得到什么?
def f(x : Option[String]) = {
// DON'T CRASH ?????
if (x != null) {
// now I can pattern match??? what is the point of the option???
e match {... , case None => ??? what was the point of this?
} else {
e match { ...// BOOM ! CRASH AND BURN because "some" is NULL??? }
}
}
答案 0 :(得分:3)
一般而言,Scala中没有任何内容禁止您通过null
。 Option[T]
是与调用者的契约,没有任何编译器强制执行它。期权合约说:“这个价值可能不存在,所以考虑到这一点”,它没有考虑到这个值可以是null
。与合同一样,它们可能会被违反,我们必须确保执行它们。
解决这个问题的一种方法是向WartRemover添加一个扩展,这是一个作为SBT工具链的一部分运行的linter(可能有类似的东西,不确定)。这样,您可以强制在编译时不将其设置为null的选项,而不是在运行时将它们分解。
这不是“这样做”的答案,因为坦率地说,今天没有一个好的解决方案OOTB。只要引用可以为null,我们就必须处理它。您必须负责代码并确保人们根据实际使用方式使用数据类型。
答案 1 :(得分:1)
您可以将case None => ...
更改为case _ => ...
,或者如果您希望以无方式处理null,则可以在无子句后面添加后者。
答案 2 :(得分:0)
正确的方法是传递可以为null的值作为选项。 e.g:
f(Option(null))
这将匹配您的无案例,不会导致匹配错误。这里的基本思想是null不应该是一个scala构造,但即使你需要处理可以为null的值,最好将它包装在一个Option中然后传递以确保与它交互的所有函数继续在正常和错误情况下正常工作。 另外,为了更详细地理解Option是如何以及为什么以这种方式实现的,你可以阅读更多关于Monads等功能结构的内容,它们为我们提供了函数式编程中的组合功能。我发现这个博客是一个很好的入门: http://danielwestheide.com/blog/2012/12/19/the-neophytes-guide-to-scala-part-5-the-option-type.html