【问题标题】:Scala Option doesn't handle null as expectedScala Option 未按预期处理 null
【发布时间】:2017-09-19 08:26:31
【问题描述】:

如果编译器在这种情况下不推断包装,我不明白在 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??? }
   }

}

【问题讨论】:

  • Option 是一种简单的数据类型,而不是编译器魔法。好的做法(大多数 Scala 库都遵循)是用 None 表示缺失的东西,如果无法避免,则仅将 null 用于 Java 互操作

标签: scala syntax pattern-matching optional


【解决方案1】:

一般来说,Scala 中没有任何内容不允许您传递nullOption[T] 是与调用者的合同,没有任何编译器强制执行。期权合约说:“这个值可能不存在,所以考虑一下”,它没有考虑到这个值可以是null。与合同一样,它们可能会被违反,我们必须确保执行它们。

解决此问题的一种方法是向WartRemover 添加扩展名,这是一个作为 SBT 工具链的一部分运行的 linter(可能已经有类似的东西,不确定)。这样,您可以强制在编译时不将选项设置为 null,而不是让它们在运行时爆炸。

这不是一个“这样做”的答案,因为坦率地说,今天没有一个好的解决方案 OOTB。只要引用可以为空,我们就必须处理它。你必须负责你的代码,并确保人们根据他们真正应该如何使用数据类型来使用它们。

【讨论】:

  • 我认为 scala 编译器会像 swift 编译器一样对待可选项。这个“选项”更像是一个“装饰器”,但没有真正的力量来帮助我编写更安全的代码。我仍然需要编写所有常规的样板检查空值等。
  • @AvnerBarr 尽管它背后没有编译器强制执行,但我不同意您必须在任何地方继续编写空检查,这样做实际上会失去语言的力量。您必须确保在编写代码库的整个团队中都遵循此约定。
  • 这是不切实际的,尤其是当您不知道谁在调用您的代码库时。 IMO 正确的是,编译器不应该允许在这些情况下传入 null (因为谁知道函数背后发生了什么)或者函数不应该被允许使用函数中的值,直到它们安全地展开它(ala迅速)
  • @AvnerBarr 我同意这可能不是最佳选择,但是当需要Option[T] 时调用您的代码并通过null 的人不值得您的图书馆IMO 提供任何“保证”。
  • 刚刚发现这是 scala 的特性。并不是要展开完整的讨论。我想也许我做错了什么,但我现在意识到这是一个语言决定
【解决方案2】:

您可以将case None => ... 更改为case _ => ...,或者如果您想以与None 不同的方式处理null,则将后者添加到None 子句之后。

【讨论】:

    【解决方案3】:

    正确的做法是将可以为 null 的值作为选项传递。例如:

    f(Option(null))
    

    这将匹配您的 None 情况,不会导致匹配错误。这里的基本思想是 null 不应该是 scala 构造,但即使您需要处理可以为 null 的值,最好将其包装在 Option 中,然后传递以确保与它交互的所有函数继续在正常和错误情况下工作正常。 此外,要更详细地了解 Option 是如何以及为什么以这种方式实现的,您可以阅读更多关于函数式构造的信息,例如 Monads,它们为我们提供了函数式编程中组合的力量。我发现这个博客是一个很好的入门入门: http://danielwestheide.com/blog/2012/12/19/the-neophytes-guide-to-scala-part-5-the-option-type.html

    【讨论】:

    • 如果我必须明确写 Option(null) 我什么也得不到。不妨在方法本身中检查 null 。 Optional 类型的想法是使编译器能够强制执行正确性和处理这些情况
    • 对。但我假设您没有为空值编写函数,而是为非空值编写函数,并且需要一种机制来处理空值。
    • 关于这个“我一无所获”,我不同意,Option(null) 不会在您的代码分支(在逻辑级别,而不是实现级别)中重新生成,结果是代码的复杂性是减少
    猜你喜欢
    • 1970-01-01
    • 2018-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多