【问题标题】:Best practice for null-checking in ScalaScala 中空值检查的最佳实践
【发布时间】:2014-06-02 10:07:43
【问题描述】:

我知道 null 在 Scala 中是不受欢迎的,并且应该始终将可选值包含在 Option 中(或者如果有可用的“null 类型”)。

优点很明显,永远不需要检查 null 值,生成的代码更安全,更易于阅读。

然而,在实践中,没有什么能阻止值成为null - 该规则不是由编译器强制执行的,更像是君子协定。例如,在与 Java API 交互时,这很容易被破坏。

这有最佳实践吗?例如,假设我需要编写一个Url 案例类,并且可以从java.net.URI 创建该类的实例:

object Url {
  def apply(uri: URI): Url = Url(uri.getScheme, uri.getHost, uri.getRawPath)
}

case class Url(protocol: String, host: String, path: String) {
  def protocol(value: String): Url = copy(protocol = value)
  def host(value: String): Url = copy(host = value)
  def path(value: String): Url = copy(path = value)
}

URI 实例可以为getSchemegetHostgetRawPath 返回null。在apply(URI) 方法(例如require 语句)中防止这些被认为是足够的吗?从技术上讲,为了完全安全,最好保护protocolhostpath 辅助方法以及构造函数,但这听起来像是大量的工作和样板。

是否认为安全?如果他们这样做了责备他们?

【问题讨论】:

    标签: scala


    【解决方案1】:

    在处理纯函数时,最好坚持完全实现,而不是使用nullrequire 或异常抛出来编码数据中的所有故障。像OptionEither 这样的类型正是为此而存在的。它们都是 monad,因此您可以对它们使用“for”-语法。

    以下对代码的修改显示了一个总函数apply,它仅在输入Java URI 不提供nulls 时产生有意义的值。我们通过将结果包装在Option 中来编码“有意义”的概念。

    object Url {
      def apply(uri: java.net.URI): Option[Url] =
        for {
          protocol <- Option(uri.getScheme)
          host <- Option(uri.getHost)
          path <- Option(uri.getRawPath)
        }
        yield Url(protocol, host, path)
    }
    
    case class Url(protocol: String, host: String, path: String)
    

    函数Option 是一个标准的空值检查函数,它将null 映射到None 并将值包装在Some 中。


    关于您的“设置”功能,您可以使用Option 类似地在它们中实现null-checking。例如:

    case class Url(protocol: String, host: String, path: String) {
      def protocol(value: String): Option[Url] = 
        Option(value).map(v => copy(protocol = v))
      // so on...
    }
    

    但是我建议不要这样做。在 Scala 中,从不使用 nulls 是惯例,因此当您从 Java 库获取值时,只为“桥”API 实现 null-handling 也是惯例。这就是为什么在从java.net.URI 转换时null-checking 确实很有意义,但在那之后你就进入了Scala 世界,那里不应该有nulls,因此null-checking 就变得多余了。

    【讨论】:

    • 值得一提的是,nullCheck 只是 Scala 中的 Option object
    • 谢谢,你的观点很好,我理解。不过,我觉得它没有解决保护助手protocolhostpath 方法的问题,还是我遗漏了什么?我是否应该考虑调用者永远不会通过null
    • 不保护他们是什么意思?他们都不能成为null
    • @IonuțG.Stan 感谢您的纠正。我完全忘记了。
    • @goral 怎么样url.copy(protocol = null),甚至Url(null, null, null)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-18
    • 1970-01-01
    • 1970-01-01
    • 2013-06-05
    • 2010-09-27
    • 2020-04-04
    • 1970-01-01
    相关资源
    最近更新 更多