我明白那个 null 在Scala中不受欢迎,并且应始终将可选值包装在一个 Option (或“null type”,如果有的话)。
优点很明显,永远不需要检查 null 值和结果代码更安全,更舒适。
然而,在实践中,没有什么可以阻止价值 null - 规则不是由编译器强制执行的,而是更多的绅士协议。例如,在与Java API交互时,这很容易破坏。
这有最好的做法吗?比方说,我需要写一个 Url case类,并且可以从a创建此类的实例 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 实例可以返回 null 对于 getScheme, getHost 和 getRawPath。它被认为足以防止这些 apply(URI) 方法(用 require 陈述,例如)?从技术上讲,为了完全安全,最好是保护 protocol, host 和 path 辅助方法,以及构造函数,但这听起来像是一个非常多的工作和样板。
相反,它是否被认为是安全的,以防止已知接受/返回的API null 价值观(URI 在我们的示例中)并假设外部调用者将不会通过 null 价值观或只是责备他们呢?
在处理纯函数时,总是更好地坚持总体实现而不是使用 null, require 或抛出异常,以编码数据中的所有故障。类似的类型 Option 和 Either 真的是那样的。它们都是monad,所以你可以使用“for”-syntax来实现它们。
对代码的以下修改显示了一个总函数 apply,当输入Java时,它只产生有意义的值 URI 提供没有 null秒。我们通过包装结果来编码“有意义”的概念 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。
关于“设置”功能,您可以实现 null - 使用相似的方式检查它们 Option。例如。:
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,所以只有实施它才是常规的 null当从Java库中获取值时,处理“桥”API。这就是为什么 null转换时,检查确实很有意义 java.net.URI,但在那之后你就在斯卡拉世界,那里应该没有 nulls,因此 null - 检查只是变得多余。
在处理纯函数时,总是更好地坚持总体实现而不是使用 null, require 或抛出异常,以编码数据中的所有故障。类似的类型 Option 和 Either 真的是那样的。它们都是monad,所以你可以使用“for”-syntax来实现它们。
对代码的以下修改显示了一个总函数 apply,当输入Java时,它只产生有意义的值 URI 提供没有 null秒。我们通过包装结果来编码“有意义”的概念 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。
关于“设置”功能,您可以实现 null - 使用相似的方式检查它们 Option。例如。:
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,所以只有实施它才是常规的 null当从Java库中获取值时,处理“桥”API。这就是为什么 null转换时,检查确实很有意义 java.net.URI,但在那之后你就在斯卡拉世界,那里应该没有 nulls,因此 null - 检查只是变得多余。