8

Option两种启动对象的方式的优缺点是什么:

1.

def getAmount: Option[Int] = {
  val a: Int = 1
  Option(a)
}

2.

def getAmount: Option[Int] = {
  val a: Int = 1
  Some(a)
}

我应该使用哪个?

4

2 回答 2

20

有两个重要的区别。首先,如果其参数为空,Option则返回 a :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)is Some[Whatever], not的返回类型Option[Whatever],这在某些情况下可能非常不方便,因为Some推断意味着您在尝试使用时NoneOption稍后在某些位置会遇到类型错误。在这些情况下,您必须使用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 的互操作性)。Some(foo)在值已显式键入为 的情况下使用Option。如果推断的类型是Some[Whatever],请添加: Option[Whatever]类型注释,或使用类似 Scalaz 的some.

于 2015-04-11T15:29:49.657 回答
0

对我来说,这只是一个常识问题。当然你可以想象这样的情况,你期望某些类型的东西是 Some and None 是不允许的。但通常第二种方式看起来更自然:返回类型是 Option,实际实现是 Some(x) 或 None。从技术上讲,从源代码中,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很好地解释了对象的用例。

于 2015-04-11T15:34:23.847 回答