在Scala中相当于JavaScript运算符||的是什么?

6
在JavaScript中,我们可以这样做:
value = f1() || f2() || f3();

如果结果不为空,这将调用f1并将其分配给value。 只有在结果为空的情况下,才会调用f2,并将其分配给value(如果不为空)。 ...

在Scala中实现此功能的方法如下:如何使此first-not-null-result函数更加优雅/简洁? 创建一个getFirstNNWithOption函数,直到非空为止调用每个函数:

value = getFirstNNWithOption(List(f1 _, f2 _, f3 _))

然而,这种方式不如JavaScript中的||运算符灵活。例如:
value = f1() || f2(3|| f3(44, 'ddd') || value4;

有没有在Scala中实现这个的方法?
5个回答

11

由于您使用的是返回Option的函数。

最好的解决方案是使用链式选项,就像这里Option's chaining所解释的那样。

所以您可以这样做:

f1().orElse(f2()).orElse(f3()).orElse(Some(4))

这实际上与@Peter Schmitz的解决方案相同。没有 pimp my lib 模式,可以避免使用 Some() 对字面值进行样板处理并具有所需的外观。因此,我将添加一个链接作为注释,指向我建议的内容。那仍然是必读的。 - Andy Petrella

9
我正在使用建议的Option替代null
例如:
class OptionPimp[T](o: Option[T]) {
  def ||(opt: => Option[T]) = o orElse opt
  def ||(t: => T) = o getOrElse t
}
implicit def optionPimp[T](o: Option[T]) = new OptionPimp(o)

def f1(): Option[Int] = None
def f2(): Option[Int] = None
def f3(): Option[Int] = Some(3)

val value1 = f1() || f2() || f3() || 4 // yields 3
val value2 = f1() || f2()         || 4 // yields 4

请阅读此文章,其中详细解释了链式编程。http://daily-scala.blogspot.com/2010/02/chaining-options-with-orelse.html - Andy Petrella
可能值得对此进行内联分块,否则所有这些按名称调用的参数... - Ryan Leach

5

如果您正在使用可能返回null的函数,您还可以定义一个null合并运算符:

class NullOption[A <: AnyRef](a: A) {
  def |?|[B >: A](b: => B) = if (a ne null) a else b
}
implicit def null_handling[A <: AnyRef](a: A) = new NullOption(a)

它的工作方式与Javascript的类似。(我使用|?|来避免将其误认为是布尔逻辑或,但如果您喜欢,可以使用||)。如果您添加一个条件映射(这里命名为?-选择您喜欢的单词或符号),这将更有效--几乎像Option--:

class NullOption[A <: AnyRef](a: A) {
  def |?|[B >: A](b: => B) = if (a ne null) a else b
  def ?[C >: Null](f: A => C): C = if (a ne null) f(a) else null
}
implicit def null_handling[A <: AnyRef](a: A) = new NullOption(a)

那么你可以:
scala> val s: String = null
s: String = null

scala> val t: String = "foo"
t: String = foo

scala> s?(_.toUpperCase) |?| t |?| { println("I am not executed"); "bar" }
res4: java.lang.String = "foo"

当然,你的类型系统不能帮助你记住需要处理无数据情况,但它可以使空值处理稍微更加愉快(至少只要没有原始类型;对于原始类型,返回null或原始类型并不是很有意义)。

4

我和Andy的意见差不多,只是我会使用操作符表示,并使用默认的正确方法:

value = f1 orElse f2(3) orElse f3(44, 'ddd') getOrElse value4

1

使用新的Scala 2.10,您可以使用隐式类来更新@PeterSchmitz的答案,因此您不需要定义隐式转换函数。

implicit class OptionPimp[T](o: Option[T]) {
  def ||(opt: => Option[T]) = o orElse opt
  def ||(t: => T) = o getOrElse t
}

同样适用于Rex Kerr的答案:

implicit class NullOption[A <: AnyRef](a: A) {
  def |?|[B >: A](b: => B) = if (a ne null) a else b
  def ?[C >: Null](f: A => C): C = if (a ne null) f(a) else null
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接