使用 Option 而不是 Null

在 Java(和其他语言)中,使用 null 是表示没有附加到引用变量的值的常用方法。在 Scala 中,使用 Option 比使用 null 更受欢迎。Option 包含可能null 的值。

None 是包含空引用的 Option 的子类。Some 是包含非空引用的 Option 的子类。

包装参考很容易:

val nothing = Option(null) // None
val something = Option("Aren't options cool?") // Some("Aren't options cool?")

这是调用可能返回 null 引用的 Java 库时的典型代码:

val resource = Option(JavaLib.getResource())
// if null, then resource = None
// else resource = Some(resource)

如果 getResource() 返回 null 值,则 resource 将成为 None 对象。否则它将是一个 Some(resource) 对象。处理 Option 的首选方法是使用 Option 类型中的高阶函数。例如,如果你想检查你的值是不是 None(类似于检查 value == null),你会使用 isDefined 函数:

val resource: Option[Resource] = Option(JavaLib.getResource())
if (resource.isDefined) {  // resource is `Some(_)` type
  val r: Resource = resource.get
  r.connect()
}

同样,要检查 null 参考,你可以这样做:

val resource: Option[Resource] = Option(JavaLib.getResource())
if (resource.isEmpty) { // resource is `None` type.
  System.out.println("Resource is empty! Cannot connect.")
}

你最好将 Option 视为 monad 并使用 foreach 处理 Option 的包装值(不使用’特殊’Option.get 方法)的条件执行:

val resource: Option[Resource] = Option(JavaLib.getResource())
resource foreach (r => r.connect())
// if r is defined, then r.connect() is run
// if r is empty, then it does nothing

如果需要 Resource 实例(与 Option[Resource] 实例相比),你仍然可以使用 Option 来防止空值。这里 getOrElse 方法提供了一个默认值:

lazy val defaultResource = new Resource()
val resource: Resource = Option(JavaLib.getResource()).getOrElse(defaultResource)

Java 代码不会轻易处理 Scala 的 Option,因此在将值传递给 Java 代码时,打开 Option,传递 null 或合理的默认值是一种很好的形式:

val resource: Option[Resource] = ???
JavaLib.sendResource(resource.orNull)
JavaLib.sendResource(resource.getOrElse(defaultResource)) //