2012-01-04 57 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 
}