我如何将这个丑陋的衬垫转换为干净的 scala 以供理解?
How do I convert this ugly one liner into a clean scala for comprehension?
嘿伙计们,我得到了这个丑陋的东西:
val test = Some(Map("TesT",123))
val keys = test.getOrElse(Map()).keys.map(_.toLowerCase).asInstanceOf[Set[String]]
require(keys.contains("test")
我可以将它(第 2 行)变成 clean/readable 以便理解吗?
这是我的尝试:
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
^
理解只是map
/flatMap
的语法糖。 Option
returns 另一个Option
的flatMap
方法。要获得多个值,您应该从序列开始,所以第一行应该是 map <- test.toSeq
。这解释了第二条错误消息。
理解中的第二行尝试使用 flatMap
访问 keys
。它可以通过两种方式修复。要么用 val keys = map.keys
替换它,这样 map
或 flatMap
都不涉及,或者完全删除此行以调用第三个: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
你原来的:
val keys = for {
map <- test
keys <- map.keys
k <- keys
} yield k.toLowerCase
for comprehension 优于 flatmap
和 map
的一个限制是它始终需要 same kind of enumerator(真正的 monad),首先建立哪种。在您的示例中,第一个 enumerator 是一个 Option
,因此它期望 map.keys
和 keys
也是 Option
类型.
您的示例的另一个问题是 keys
实际上是从集合 map.keys
中提取的单个 key
... 因此 k
将引用一个enumurator 中 keys: String
.
中的字符
通过将 for
理解的初始类型转换为 Seq
来解决 for-comprehension 类型问题,允许以下术语属于那个类型(他们是),然后在提取 key
:
后停止
val keys = for {
map <- test.toSeq
key <- map.keys
} yield key.toLowerCase
你不需要理解这个。
清楚地对操作进行排序,并明确地拼出步骤通常更清晰易读。只是不要试图将内容塞进一行:
test
.iterator
.flatMap(_.keys)
.map(_.toLowerCase)
.contains("test")
嘿伙计们,我得到了这个丑陋的东西:
val test = Some(Map("TesT",123))
val keys = test.getOrElse(Map()).keys.map(_.toLowerCase).asInstanceOf[Set[String]]
require(keys.contains("test")
我可以将它(第 2 行)变成 clean/readable 以便理解吗?
这是我的尝试:
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
^
理解只是map
/flatMap
的语法糖。 Option
returns 另一个Option
的flatMap
方法。要获得多个值,您应该从序列开始,所以第一行应该是 map <- test.toSeq
。这解释了第二条错误消息。
理解中的第二行尝试使用 flatMap
访问 keys
。它可以通过两种方式修复。要么用 val keys = map.keys
替换它,这样 map
或 flatMap
都不涉及,或者完全删除此行以调用第三个: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
你原来的:
val keys = for {
map <- test
keys <- map.keys
k <- keys
} yield k.toLowerCase
for comprehension 优于 flatmap
和 map
的一个限制是它始终需要 same kind of enumerator(真正的 monad),首先建立哪种。在您的示例中,第一个 enumerator 是一个 Option
,因此它期望 map.keys
和 keys
也是 Option
类型.
您的示例的另一个问题是 keys
实际上是从集合 map.keys
中提取的单个 key
... 因此 k
将引用一个enumurator 中 keys: String
.
通过将 for
理解的初始类型转换为 Seq
来解决 for-comprehension 类型问题,允许以下术语属于那个类型(他们是),然后在提取 key
:
val keys = for {
map <- test.toSeq
key <- map.keys
} yield key.toLowerCase
你不需要理解这个。 清楚地对操作进行排序,并明确地拼出步骤通常更清晰易读。只是不要试图将内容塞进一行:
test
.iterator
.flatMap(_.keys)
.map(_.toLowerCase)
.contains("test")