2012-01-04 128 views
6

在JavaScript中,我们可以这样做:在斯卡拉

value = f1() || f2() || f3(); 

这将调用F1,并将其分配给值,如果结果不为空。 只有当结果为空时,它才会调用f2,如果它不为null,则将其赋值为值。 ...

的一种方式在Scala中实现,这是这里给出:How to make this first-not-null-result function more elegant/concise? 创建调用每个函数,直到没有空一getFirstNNWithOption功能:

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

然而,这并不像你一样的JavaScript ||运营商,这更加灵活。例如:

value = f1() || f2(3) || f3(44, 'ddd') || value4; 

有没有办法在scala中实现这一点?

回答

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 
+0

请阅读本,其中链接是很好的解释。 http://daily-scala.blogspot.com/2010/02/chaining-options-with-orelse.html – 2012-01-04 11:22:27

+0

@dave好点,thx,更新! – 2012-01-04 17:31:40

+0

这可能是值得的内联块,否则所有这些通过名称参数调用... – 2017-06-13 05:20:50

11

由于您使用的函数返回Option

最好的解决办法是使用链接选项喜欢这里Option's chaining

这么解释,你会做

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

这是相同的解决方案实际上比@彼得Schmitz。 W/o皮条客我的lib模式,这有助于避免字面上的样板文件Some(),并且具有您希望的样子。所以我只是想添加一条评论链接到我建议的内容。这仍然是一个必读 – 2012-01-04 11:21:58

4

我几乎同样的观点为Andy,但我会使用运算符表示法,并使用适当的默认方法:

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

如果您将此函数与可能返回null的函数一起使用,那么也可以使用d efine null-coalescing运算符:

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" 

当然,你的类型系统不会帮助你记住,你需要处理有 - 是 - 没有数据的情况下,但它可以使空处理稍微更愉快(至少只要没有原语;使用原语返回n无论是原始的还是没有意义的)。

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 
} 

同为雷克斯科尔回答:

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 
}