构造 Option 对象的正确方法:Option(value) vs Some(value)
Proper way to construct Option object: Option(value) vs Some(value)
启动Option
对象的两种方式的优缺点是什么:
1.
def getAmount: Option[Int] = {
val a: Int = 1
Option(a)
}
2.
def getAmount: Option[Int] = {
val a: Int = 1
Some(a)
}
我应该使用哪个?
有两个重要的区别。首先,Option
将 return 一个 None
如果它的参数是 null:
scala> val x: Option[String] = Some(null)
x: Option[String] = Some(null)
scala> val y: Option[String] = Option(null)
y: Option[String] = None
这可能很有用,但它并不总是您想要的,并且(同样重要的是)它表明在某些情况下参数有可能为空,这可能会产生误导。
Some
更适用于您想要围绕您知道不为空的值生成 Option
的情况。不幸的是,第二个区别是 Some(foo)
的 return 类型是 Some[Whatever]
,而不是 Option[Whatever]
,这在某些情况下非常不方便 Some
推断意味着当您稍后尝试在某些位置使用 None
或 Option
时,您会遇到类型错误。在这些情况下,您必须使用 Some(foo): Option[Whatever]
,这是非常不愉快的。
例如,假设我们有一个表示(我们希望)整数的字符串列表,我们想要对它们进行解析和求和。如果存在解析错误,我们需要 None
,否则需要 Some(total)
。以下是使用标准库在一次遍历中执行此操作的相当合理的方法:
List("1", "2", "3").foldLeft(Some(0)) {
case (acc, item) => for {
t <- acc
n <- util.Try(item.toInt).toOption
} yield t + n
}
除非这不起作用——我们收到类型错误:
<console>:10: error: type mismatch;
found : Option[Int]
required: Some[Int]
t <- acc
^
我们可以通过写 .foldLeft(Some(0): Option[Int])
来解决这个问题,但是呃。
这在您的特定示例中不是问题,因为 return 类型明确为 Option[Int]
,因此您无需担心类型推断。那么 Some(a)
是正确的选择。
附带说明,Scalaz 提供了 some
和 none
构造函数,可帮助您避免类型推断问题和嘈杂的解决方案,例如 Some(foo): Option[Whatever]
:
scala> import scalaz._, Scalaz._
import scalaz._
import Scalaz._
scala> some(10)
res0: Option[Int] = Some(10)
scala> none[Int]
res1: Option[Int] = None
两个return类型都是Option
,这使得类型推断更容易。如果你不想使用 Scalaz,你可以自己简单地定义这些:
scala> def some[A](a: A): Option[A] = Some(a)
some: [A](a: A)Option[A]
scala> def none[A]: Option[A] = None
none: [A]=> Option[A]
如果您使用这些而不是 Some
和 None
,您永远不必担心会推断出不恰当的特定类型。
总结一下:仅在参数可能为空的情况下使用 Option(foo)
(理想情况下应该只用于与 Java 的互操作性)。在值已明确键入为 Option
的情况下使用 Some(foo)
。如果推断类型为 Some[Whatever]
,请添加 : Option[Whatever]
类型注释,或使用类似 Scalaz 的 some
.
对我来说这只是一个常识问题。当然,您可以想象这样一种情况,即您期望完全属于 Some 类型,而 None 是不允许的。但通常第二种方式看起来更自然:return 类型是 Option,实际实现是 Some(x) 或 None。从技术上讲,从 source code,Option(x) 调用伴随对象的 apply()
方法:
object Option {
import scala.language.implicitConversions
implicit def option2Iterable[A](xo: Option[A]): Iterable[A] = xo.toList
def apply[A](x: A): Option[A] = if (x == null) None else Some(x)
def empty[A] : Option[A] = None
}
并且 Some(a) 在案例 class..
上调用 apply()
方法
final case class Some[+A](x: A) extends Option[A] {
def isEmpty = false
def get = x
}
其他方法同理。 null
对象的用例在 Travis Brown 答案中得到了很好的解释。
启动Option
对象的两种方式的优缺点是什么:
1.
def getAmount: Option[Int] = {
val a: Int = 1
Option(a)
}
2.
def getAmount: Option[Int] = {
val a: Int = 1
Some(a)
}
我应该使用哪个?
有两个重要的区别。首先,Option
将 return 一个 None
如果它的参数是 null:
scala> val x: Option[String] = Some(null)
x: Option[String] = Some(null)
scala> val y: Option[String] = Option(null)
y: Option[String] = None
这可能很有用,但它并不总是您想要的,并且(同样重要的是)它表明在某些情况下参数有可能为空,这可能会产生误导。
Some
更适用于您想要围绕您知道不为空的值生成 Option
的情况。不幸的是,第二个区别是 Some(foo)
的 return 类型是 Some[Whatever]
,而不是 Option[Whatever]
,这在某些情况下非常不方便 Some
推断意味着当您稍后尝试在某些位置使用 None
或 Option
时,您会遇到类型错误。在这些情况下,您必须使用 Some(foo): Option[Whatever]
,这是非常不愉快的。
例如,假设我们有一个表示(我们希望)整数的字符串列表,我们想要对它们进行解析和求和。如果存在解析错误,我们需要 None
,否则需要 Some(total)
。以下是使用标准库在一次遍历中执行此操作的相当合理的方法:
List("1", "2", "3").foldLeft(Some(0)) {
case (acc, item) => for {
t <- acc
n <- util.Try(item.toInt).toOption
} yield t + n
}
除非这不起作用——我们收到类型错误:
<console>:10: error: type mismatch;
found : Option[Int]
required: Some[Int]
t <- acc
^
我们可以通过写 .foldLeft(Some(0): Option[Int])
来解决这个问题,但是呃。
这在您的特定示例中不是问题,因为 return 类型明确为 Option[Int]
,因此您无需担心类型推断。那么 Some(a)
是正确的选择。
附带说明,Scalaz 提供了 some
和 none
构造函数,可帮助您避免类型推断问题和嘈杂的解决方案,例如 Some(foo): Option[Whatever]
:
scala> import scalaz._, Scalaz._
import scalaz._
import Scalaz._
scala> some(10)
res0: Option[Int] = Some(10)
scala> none[Int]
res1: Option[Int] = None
两个return类型都是Option
,这使得类型推断更容易。如果你不想使用 Scalaz,你可以自己简单地定义这些:
scala> def some[A](a: A): Option[A] = Some(a)
some: [A](a: A)Option[A]
scala> def none[A]: Option[A] = None
none: [A]=> Option[A]
如果您使用这些而不是 Some
和 None
,您永远不必担心会推断出不恰当的特定类型。
总结一下:仅在参数可能为空的情况下使用 Option(foo)
(理想情况下应该只用于与 Java 的互操作性)。在值已明确键入为 Option
的情况下使用 Some(foo)
。如果推断类型为 Some[Whatever]
,请添加 : Option[Whatever]
类型注释,或使用类似 Scalaz 的 some
.
对我来说这只是一个常识问题。当然,您可以想象这样一种情况,即您期望完全属于 Some 类型,而 None 是不允许的。但通常第二种方式看起来更自然:return 类型是 Option,实际实现是 Some(x) 或 None。从技术上讲,从 source code,Option(x) 调用伴随对象的 apply()
方法:
object Option {
import scala.language.implicitConversions
implicit def option2Iterable[A](xo: Option[A]): Iterable[A] = xo.toList
def apply[A](x: A): Option[A] = if (x == null) None else Some(x)
def empty[A] : Option[A] = None
}
并且 Some(a) 在案例 class..
上调用apply()
方法
final case class Some[+A](x: A) extends Option[A] {
def isEmpty = false
def get = x
}
其他方法同理。 null
对象的用例在 Travis Brown 答案中得到了很好的解释。