构造Option对象的正确方法:Option(value)vs Some(value)

时间:2015-04-11 15:09:55

标签: 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)
}

我应该使用哪个?

2 个答案:

答案 0 :(得分:19)

有两个重要的区别。首先,如果Option的参数为null,则None将返回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)的情况。不幸的是,第二个区别是Some[Whatever]的返回类型是Option[Whatever],而不是Some,这在某些情况下非常不方便,因为None推断意味着你会得到当您稍后尝试在某些位置使用OptionSome(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),因此您无需担心类型推断。在这种情况下,some是正确的选择。

作为旁注,Scalaz提供noneSome(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

两种返回类型都是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] ,这使得类型推断变得更加容易。如果您不想使用Scalaz,您可以自己轻松定义这些:

Some

如果您使用这些代替NoneOption(foo),则永远不必担心会推断出不恰当的特定类型。

总结一下:仅在参数可能为null的情况下使用Some(foo)(理想情况下应该仅用于与Java的互操作性)。如果值已明确键入Option,请使用Some[Whatever]。如果推断类型为: Option[Whatever],请添加some类型注释,或使用类似Scalaz的{{1}}。

答案 1 :(得分:0)

至于我,这只是一个常识问题。当然,你可以想象你期望的东西完全类型的情况Some和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
}

有些(a)在案例类上调用apply()方法..

final case class Some[+A](x: A) extends Option[A] {
  def isEmpty = false
  def get = x
}

所有其他方法都是相同的。在Travis Brown答案中很好地解释了null个对象的用例。