使用选项所有的地方感觉有点别扭。难道我做错了什么?
-
21-09-2019 - |
题
由于我看了一下Option
类可以帮助你避免NullPointerException异常的文章因此,我开始使用它所有的地方。想象一下这样的:
var file:Option[File] = None
和后,当我使用它:
val actualFile = file.getOrElse(new File("nonexisting"))
if(actualFile.getName.equals("nonexisting")) { // instead of null checking
}
else { // value of file was good
}
做这样的东西不觉得所有的“正确”给我。我还注意到,.get
已成为过时。 。这有点东西你们与期权做什么太,还是我走错了路?
解决方案
这是一般不返回Option
然后用getOrElse
生产,意思是“未找到”的一些标记值是个好主意。这就是Option
是专为:以表示值未找到
Option
真正体现出它的功率与像map
和foreach
函数编程结构结合使用时。有多个选项时,这是最有效的。例如,假设我写这需要一个字符串,并给我回一个文件的方法,但只有当该文件存在,并且是一个文件不是一个目录:
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
}
到目前为止,使用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))
看发生了什么事!在前一种情况下,我们不得不做手工逻辑测试和创建临时变量。啊!在第二种情况下,map
做了所有的脏活我们:没有被映射到无,Some(file)
被映射到Some(fileinputstream)
。简单!
但它变得更好的。也许我们要找出一大堆文件的大小:
def totalSize2(ss: Seq[String]) = {
(0L /: ss.flatMap(niceFile2)){(sum,f) => sum+f.length}
}
等待,这到底是怎么回事 - 怎么样所有None
?难道我们没有注意,不知怎么处理?嗯,这就是flatMap
进来:它合并所有的答案到一个列表。 None
是长度为零的答案,因此它会忽略它。 Some(f)
有一个答案 - f
- 因此它把它在列表中。然后,我们用折叠加起来所有的长度 - 现在,在列表中的所有元素都是有效的。相当不错!
其他提示
这是一个好主意,为无法解决的的Option
的价值,而是要的适用的逻辑,无论是它包含:
findFile.foreach(process(_))
基本上,如果找到一个这样处理一个File
和不执行任何其它方式(并且等同于Thomas的第一for
理解因为for
编译为一个呼叫到foreach
)。它是一个更简洁版本:
findFile match {
case Some(f) => process(f)
case None =>
}
更重要的是,关于这个伟大的事情是,你可以的链的操作是这样的:
(findLiveFile orElse fileBackupFile orElse findTempFile).foreach(process(_)
在大多数情况下,你可以使用模式匹配
file match {
case Some(f) => { .. } //file is there
case _ => { .. } //file is not there
}
如果你只在文件中有兴趣,如果它的存在,你可以使用一个表达
for(f <- file) { //file is there
}
可以然后链表达式来在多个级别上工作,在容器上的
for{
option <- List(Some(1), None, Some(2))
f <- option
} yield f
res0: List[Int] = List(1, 2)
另外,您可以使用isDefined并获得:
if(option.isDefined) {
val x = option.get;
} else {
}
得到的是未在Scala中弃用2.8.0.Beta-1。
下面是一种替代方案:
var file:Option[File] = None
// ...
file map (new File(_)) foreach { fh =>
// ...
}
不过,如果你需要的,如果该文件存在,而其他的东西,如果不是这样,一个match
说法是比较合适做一些事情:
var file:Option[File] = None
// ...
file map (new File(_)) match {
case Some(fh) =>
// ...
case None =>
// ...
}
这几乎是相同的作为if
声明,但我喜欢它更好的链接性质的东西像Option
,在这里我想提取的值也是如此。
晴重申大家都在说,但我觉得有,当你有一个可为空VAR这样你会遇到至少4种不同的情况:
1.文件不能为空
load(file.get())
当您尝试实际使用的文件会抛出异常。快速失败,耶!
2.文件为空,但是在这种情况下,我们有一个合理的默认:结果
load(file.getOrElse(new File("/defaultFile")))
3.两个逻辑的分支基于该文件是否存在:
file match {
case Some(f) => { .. } //file is there
case _ => { .. } //file is not there
}
4.空操作,如果该文件是空,又名静默失败。我不认为这是一个非常往往是最好的我在现实生活中:
for (f <- file) {
//do some stuff
}
或者,也许更清楚?
if (f.isDefined) {
//do some stuff
}