在整个地方使用Option感觉有点尴尬.难道我做错了什么?

Geo*_*Geo 7 scala scala-option

作为文章的结果,我读到了Option有助于避免NullPointerException的类,我开始在整个地方使用它.想象一下这样的事情:

var file:Option[File] = None
Run Code Online (Sandbox Code Playgroud)

以后当我使用它时:

val actualFile = file.getOrElse(new File("nonexisting"))
if(actualFile.getName.equals("nonexisting")) { // instead of null checking

}
else { // value of file was good

}
Run Code Online (Sandbox Code Playgroud)

做这样的事情对我来说感觉不那么"正确".我也注意到.get已经被弃用了..这种东西是你们用Option做的,或者我走错了路?

Rex*_*err 15

返回Option然后getOrElse用来产生一些意味着"未找到"的哨兵值通常不是一个好主意.这就是为什么Option设计:表示没有找到值!

Option真正体现出它的力量与像函数编程结构结合使用时mapforeach.在处理多个选项时,这是最有效的.例如,假设我编写了一个接受字符串并返回文件的方法,但只有当文件存在并且文件不是目录时:

import java.io._;
def niceFile1(s: String): File = {
  val f = new File(s);
  if (f.exists && !f.isDirectory) f else null
}
def niceFile2(s: String): Option[File] = {
  val f = new File(s);
  if (f.exists && !f.isDirectory) Some(f) else None
}
Run Code Online (Sandbox Code Playgroud)

到目前为止,使用起来null更容易 - 至少在您忘记这可能会给您null并且您获得NPE之前.无论如何,我们现在尝试使用它.

def niceFopen1(s: String) = {
  val f = niceFile1(s);
  if (f!=null) new FileInputStream(f) else null;
}
def niceFopen2(s: String) = niceFile2(s).map(f => new FileInputStream(f))
Run Code Online (Sandbox Code Playgroud)

看看发生了什么!在前一种情况下,我们必须手动进行逻辑测试并创建临时变量.啊! 在第二种情况下,map为我们完成了所有脏工作:None映射到None,并Some(file)映射到Some(fileinputstream).简单!

但它变得更好了.也许我们想找到一大堆文件的大小:

def totalSize2(ss: Seq[String]) = {
  (0L /: ss.flatMap(niceFile2)){(sum,f) => sum+f.length}
}
Run Code Online (Sandbox Code Playgroud)

等等,这里发生了什么 - 所有这一切None呢?我们不是必须注意并以某种方式处理它们吗?嗯,这就是它的所在flatMap:它将所有答案连接在一起. None是零长度的答案,所以它忽略了它. Some(f)有一个答案 - f- 它把它放在列表中.然后我们使用折叠来累加所有长度 - 现在列表中的所有元素都是有效的.挺棒的!

  • 我特意说了_sentinel_值,而不是_default_值.我同意默认值很有用.Sentinels - 一个对象,其唯一目的是指示一些异常情况或列表的结尾或其他 - 几乎从不.然而,也许我选择的措词会被误解. (4认同)

oxb*_*kes 12

不解决它的值Option,但逻辑应用于它包含的任何内容是一个好主意:

findFile.foreach(process(_))
Run Code Online (Sandbox Code Playgroud)

基本上这会处理一个File如果找到一个并且什么都不做(并且相当于托马斯的第一个for理解因为for编译到一个调用foreach).它是一个更简洁的版本:

findFile match {
  case Some(f) => process(f)
  case None =>
}
Run Code Online (Sandbox Code Playgroud)

更重要的是,关于这一点的好处是你可以连锁经营,例如:

(findLiveFile orElse fileBackupFile orElse findTempFile).foreach(process(_)
Run Code Online (Sandbox Code Playgroud)


Tho*_*ung 7

在大多数情况下,您将使用模式匹配

file match {
   case Some(f) => { .. } //file is there
   case _ => { .. } //file is not there 
}
Run Code Online (Sandbox Code Playgroud)

如果您只对该文件感兴趣,则可以使用for表达式

for(f <- file) { //file is there 
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以链接表达式以在容器上的多个级别上工作

for{ 
  option <- List(Some(1), None, Some(2))
  f <- option
} yield f

res0: List[Int] = List(1, 2)
Run Code Online (Sandbox Code Playgroud)

或者你可以使用isDefined并得到:

if(option.isDefined) {
   val x = option.get;
} else {
}
Run Code Online (Sandbox Code Playgroud)

Scala 2.8.0.Beta-1中不推荐使用get.