2014-11-05 53 views
6

我有以下的收益環路發生在一個布爾值,應該要麼產生一些(字符串)或無,取決於布爾:如果我將一個選項傳遞給它,Scala是否可以返回None?

val theBoolean = false 

val x: Option[String] = 
for { 
    theArg <- theBoolean 
} yield { 
    if (theArg) { 
    "abc" 
    } else { 
    None 
    } 
} 

這個偉大的工程,如果theBoolean實際上是一個布爾像false。但是,如果我想在傳遞一個Option[Boolean]

val theBoolean = Some(false) 

好像斯卡拉自動應用部分()包裝到無回報 - 我收到一宗投訴,「類型選項中的表達[Serializable接口]不符合到期望的類型Option [String]「(無可序列化)。產量是完全滿意相同的字符串返回,雖然(它不會成爲一個選項[選項[字符串]

我怎麼會在這種情況下返回無?

+1

我發現None.get實際上使編譯器高興的差異。但這樣使用它似乎很奇怪。 – Nathan 2014-11-05 00:52:28

+0

這段代碼試圖實現什麼? – 2014-11-05 00:57:26

+0

一個選項被傳入 - 在某些條件下,我想從中提取一個字符串,但在其他條件下,我希望它是None。 – Nathan 2014-11-05 00:59:40

回答

13

一種-理解僅僅是一系列flatMapmapfilter語法糖。 讓我們desugar你的代碼:

val theBoolean = Some(false) 

val x = theBoolean.map { theArg => 
    if (theArg) { 
    "abc" 
    } else { 
    None 
    } 
} 

正如你所看到的,你只是在Option的值映射,所以你要麼返回Some(abc)Some(None)None(如果theBoolean已經None) 。

最低的普通型的None和​​是java.Serializable,所以這就是爲什麼x類型被推斷爲Option[Serializable],這是毫無意義的Option[Any]

可能的解決方案是:

  • 使用flatMap

    theBoolean.flatMap(theArg => if (theArg) Some("abc") else None) 
    

    或甚至更短

    theBoolean.flatMap(if (_) Some("abc") else None) 
    
  • 濾波和映射

    theBoolean.withFilter(identity).map(_ => "abc") 
    

由於您正在測試值本身,因此我使用了identity

顯然,你總是可以利用通過換理解提供的語法糖,雖然它並沒有真正在這種情況下

for { 
    theArg <- theBoolean 
    if theArg 
} yield "abc" 
+0

謝謝,解釋細目非常有幫助! – Nathan 2014-11-05 02:15:33

1

你是對的,一切內yield塊被包裝到一個Option中(這就是對選項的理解是如何工作的)通常,for-comprehensions描述了應該如何處理可以在monad內部找到的內容,而在這個內容中調用了for-comprehension,但是結束結果(對於yield塊以外的世界)仍然是同一類型的單子(例如選項,嘗試或列表)

更多一般說明:有很多描述關於monad是什麼的tions。你可以假設一個monad就是那個臭名昭着的Schrödinger盒子,你在思考那隻隱藏在那裏的貓會發生什麼,但是這一切仍然存在,因爲盒子還沒有打開。

一種可能的方式做你想要什麼:

val theBoolean = false 

val x: Option[String] = 
for { 
    theArg <- theBoolean if theArg 
} yield { 
    "abc" 
} 
0

取而代之的是爲理解這聽起來像你想flatMap而不是理解力。

scala> Some(false).flatMap(if (_) Some("abc") else None) 
res4: Option[String] = None 
相關問題