2016-11-04 19 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")