我经常发现自己写的形式为Scala:
def foo = {
f1() match {
case Some(x1) => x1
case _ =>
f2() match {
case Some(x2) => x2
case _ =>
f3() match {
case Some(x3) => x3
case _ =>
f4()
}
}
}
}
这是Java的道德等同物
Object foo() {
Object result = f1();
if (result != null) {
return result;
} else {
result = f2();
if (result != null) {
return result;
} else {
result = f3();
if (result != null) {
return result;
} else {
return f4();
}
}
}
}
它看起来很丑陋而且不必要地冗长。我觉得在Scala的一行中应该有一种可读的方法,但我不清楚它是什么。
注意:我查看Idiomatic Scala for Nested Options,但情况稍有不同。
答案 0 :(得分:8)
使用Scala中的选项编写嵌套模式匹配的惯用方法是使用方法map
,flatMap
,orElse
和getOrElse
。
如果要进一步处理选项的内容并保留可选行为,请使用map
:
所以不要这样:
val opt: Option[Int] = ???
opt match {
case Some(x) => Some(x + 1)
case None => None
}
你会这样做:
val opt: Option[Int] = ???
opt.map(_ + 1)
这更自然地链接:
opt.map(_ + 1).map(_ * 3).map(_ - 2)
flatMap
完全相似,但在进一步操作返回选项类型时也会使用。
在您的特定示例中,orElse
似乎是最适合的解决方案。如果不为空,您可以使用orElse
返回选项本身,或者返回参数。请注意,该参数是延迟评估的,因此它实际上等同于嵌套模式匹配/ if-then-else。
def foo = {
f1().orElse(f2())
.orElse(f3())
.orElse(f4())
}
如果您想摆脱选项,也可以将这些与getOrElse
结合使用。在您的示例中,您似乎返回最终f4
,就好像它没有返回Option
一样,因此您将执行以下操作:
def foo = {
f1().orElse(f2())
.orElse(f3())
.getOrElse(f4())
}
答案 1 :(得分:8)
我知道我迟到了,但觉得这里的orElse
解决方案有点笨拙。对我来说,一般的功能习语(不仅仅是scalaic)会是......沿着这些路线(原谅我,我不是斯卡拉精通):
def f1 = () => { println("f1 here"); null }
def f2 = () => { println("f2 here"); null }
def f3 = () => { println("f3 here"); 2 }
def f4 = () => { println("f4 here"); 3 }
def f5 = () => { println("f5 here"); 43 }
Stream(f1, f2, f3, f4, f5)
.map(f => f())
.dropWhile(_ == null)
.head
你使用Stream作为一个惰性列表,基本上,你说:开始调用函数并给我第一个不评估为零的函数。结合声明性方法和懒惰为您提供了这个通用的代码片段,其中当函数数量发生变化时,您唯一需要更改的是输入列表(流),只需添加一个函数元素。这样,函数f1 ... fn成为数据,因此您不必修改任何现有代码。
答案 2 :(得分:5)
你可以尝试:
f1() orElse f2() orElse Option(f3()) getOrElse f4()
假设f1和f2返回相同类型的选项,f3和f4返回相同类型的非选项
修改强>
如果f3()
返回Option
或不是f1() orElse f2() orElse f3() getOrElse f4()
,示例中并不完全清楚,如果确实如此,则代码将简化为:
speedlimit
答案 3 :(得分:0)
对cmbaxter的响应略有调整,可以节省一些字符,但在其他方面是相同的。
def foo = f1 orElse f2 orElse f3 getOrElse f4