2016-11-04 43 views
2

嗨,我得到這個醜陋的東西:我該如何將這個醜陋的一個班輪轉換成一個乾淨的斯卡拉來理解?

val test = Some(Map("TesT",123)) 
val keys = test.getOrElse(Map()).keys.map(_.toLowerCase).asInstanceOf[Set[String]] 
require(keys.contains("test") 

我可以把它(線#2)到一個乾淨的/可讀的理解?

這裏是我的嘗試:

scala> val keys = for { 
    |  map <- test 
    |  keys <- map.keys 
    |  k <- keys 
    | } yield k.toLowerCase 
<console>:18: error: value toLowerCase is not a member of Char 
     } yield k.toLowerCase 
       ^
<console>:16: error: type mismatch; 
found : Iterable[Char] 
required: Option[?] 
      keys <- map.keys 
       ^
+1

「醜陋」的一個班輪在哪裏?另外...爲此目的'test.getOrElse(Map())。contains(「test」)'是一種更好的選擇。 –

回答

1

悟僅僅是map/flatMap一個語法糖。 OptionflatMap方法返回另一個Option。要獲得多個值,您應該從序列開始,因此第一行應該是map <- test.toSeq。這解釋了第二個錯誤消息。

理解的第二行嘗試使用flatMap訪問keys。它可以通過兩種方式來解決。要麼將其替換爲val keys = map.keys,因此不涉及mapflatMap,或者在第三個調用上完全刪除此行:k <- map.keys。這將修復第一個錯誤。

所以,你可以在兩個方案之間進行選擇:

val keys = for { 
     map <- test.toSeq 
     val keys = map.keys 
     k <- keys 
} yield k.toLowerCase 

val keys = for { 
     map <- test.toSeq 
     k <- map.keys 
} yield k.toLowerCase 
1

您的原始:

val keys = for { 
      map <- test 
      keys <- map.keys 
      k <- keys 
     } yield k.toLowerCase 

其中的理解的約束超過flatmapmap是它需要same kindenumerator(真的是一個單子),第一個建立哪種類型。在你的例子中,第一個枚舉器是一個Option,所以它預計map.keyskeys也是類型Option

你的榜樣的另一個問題是,keys真的是從集合map.keys採取單一key ...所以k會再指角色在enumuratorkeys: String

由初始類型for理解的轉換爲Seq,允許下列術語是該類型的(它們)解決該換理解型問題,然後停止提取key後:

val keys = for { 
     map <- test.toSeq 
     key <- map.keys 
    } yield key.toLowerCase 
3

你不需要理解這一點。清晰地排序操作,明確地將步驟拼寫出來往往更清晰可讀。只是不要試圖將東西塞進一條線:

test 
    .iterator 
    .flatMap(_.keys) 
    .map(_.toLowerCase) 
    .contains("test")