Options 的惯用 Scala 代替 if/else/else 链
Idiomatic Scala for Options in place of if/else/else chain
我经常发现自己正在编写以下形式的 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,但情况有所不同。
你可以试试:
f1() orElse f2() orElse Option(f3()) getOrElse f4()
假设 f1 和 f2 returns 相同类型的选项和 f3 和 f4 return 相同类型的非选项
编辑
如果 f3()
return 是 Option
或不是 f3()
,那么代码将简化为:
f1() orElse f2() orElse f3() getOrElse f4()
在 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
非常相似,但在您进一步操作时使用 return 选项类型。
在您的特定示例中,orElse
似乎是最适合的解决方案。如果不为空,您可以使用 orElse
到 return 选项本身,否则 return 参数。请注意,参数是延迟计算的,因此它实际上等同于嵌套模式 matching/if-then-else.
def foo = {
f1().orElse(f2())
.orElse(f3())
.orElse(f4())
}
如果你想摆脱一个选项,你也可以将它们与 getOrElse
结合起来。在您的示例中,您似乎 return 最后的 f4
就好像它没有 return 和 Option
,所以您将执行以下操作:
def foo = {
f1().orElse(f2())
.orElse(f3())
.getOrElse(f4())
}
对 cmbaxter 的响应进行了细微调整,节省了几个字符,但其他方面相同。
def foo = f1 orElse f2 orElse f3 getOrElse f4
我知道我来晚了,但觉得这里的 orElse
解决方案有点笨拙。对我来说,一般的功能习语(不仅仅是scalaic)将是……。按照这些思路(原谅我,我不精通scala):
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 就变成了数据,因此您不必修改任何现有代码。
我经常发现自己正在编写以下形式的 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,但情况有所不同。
你可以试试:
f1() orElse f2() orElse Option(f3()) getOrElse f4()
假设 f1 和 f2 returns 相同类型的选项和 f3 和 f4 return 相同类型的非选项
编辑
如果 f3()
return 是 Option
或不是 f3()
,那么代码将简化为:
f1() orElse f2() orElse f3() getOrElse f4()
在 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
非常相似,但在您进一步操作时使用 return 选项类型。
在您的特定示例中,orElse
似乎是最适合的解决方案。如果不为空,您可以使用 orElse
到 return 选项本身,否则 return 参数。请注意,参数是延迟计算的,因此它实际上等同于嵌套模式 matching/if-then-else.
def foo = {
f1().orElse(f2())
.orElse(f3())
.orElse(f4())
}
如果你想摆脱一个选项,你也可以将它们与 getOrElse
结合起来。在您的示例中,您似乎 return 最后的 f4
就好像它没有 return 和 Option
,所以您将执行以下操作:
def foo = {
f1().orElse(f2())
.orElse(f3())
.getOrElse(f4())
}
对 cmbaxter 的响应进行了细微调整,节省了几个字符,但其他方面相同。
def foo = f1 orElse f2 orElse f3 getOrElse f4
我知道我来晚了,但觉得这里的 orElse
解决方案有点笨拙。对我来说,一般的功能习语(不仅仅是scalaic)将是……。按照这些思路(原谅我,我不精通scala):
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 就变成了数据,因此您不必修改任何现有代码。