【发布时间】:2015-04-11 15:09:55
【问题描述】:
两种发起Option对象的方式的优缺点是什么:
1.
def getAmount: Option[Int] = {
val a: Int = 1
Option(a)
}
2.
def getAmount: Option[Int] = {
val a: Int = 1
Some(a)
}
我应该使用哪个?
【问题讨论】:
标签: scala scala-option
两种发起Option对象的方式的优缺点是什么:
1.
def getAmount: Option[Int] = {
val a: Int = 1
Option(a)
}
2.
def getAmount: Option[Int] = {
val a: Int = 1
Some(a)
}
我应该使用哪个?
【问题讨论】:
标签: scala scala-option
有两个重要的区别。首先,Option 将返回一个 None 如果其参数为空:
scala> val x: Option[String] = Some(null)
x: Option[String] = Some(null)
scala> val y: Option[String] = Option(null)
y: Option[String] = None
这可能很有用,但它并不总是你想要的,而且(同样重要的是)它表明在某些情况下参数可能为 null 的可能性很大,这可能会产生误导。
Some 更适合您想要围绕一个您知道不为空的值生成Option 的情况。不幸的是,第二个区别是Some(foo) 的返回类型是Some[Whatever],而不是Option[Whatever],这在某些情况下可能非常不方便,因为推断出Some 意味着当您尝试使用@ 时会出现类型错误987654331@ 或 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]) 来解决这个问题,但是啊。
在您的具体示例中这不是问题,因为返回类型明确为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
两种返回类型都是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 and None 是不允许的。但通常第二种方式看起来更自然:返回类型是 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) 在案例类上调用 apply() 方法..
final case class Some[+A](x: A) extends Option[A] {
def isEmpty = false
def get = x
}
所有其他方法都相同。 Travis Brown 答案中很好地解释了 null 对象的用例。
【讨论】:
Some[String](null)和Option[String](null)。