我正在尝试从列表选项中创建地图。所以,我有一个像这样声明的列表选项:
val authHeaders: Option[Set[String]] = Some(Set("a", "b", "c"))
我希望得到这样的地图:(a - > a,b - > b,c - > c)。
所以我试过这种方式:
for {
headers <- authHeaders
header <- headers
} yield (header -> header)
但是我收到了这个错误:
<console>:11: error: type mismatch;
found : scala.collection.immutable.Set[(String, String)]
required: Option[?]
header <- headers
^
我哪里做错了?
补充说明:这个选项让我很头疼,但我需要了解如何在任何情况下处理它。无论如何,仅仅为了比较,我尝试通过删除选项来消除头痛因素。
scala> val bah = Set("a", "b", "c")
bah: scala.collection.immutable.Set[String] = Set(a, b, c)
scala> (
| for {
| x <- bah
| } yield (x -> x)).toMap
res36: scala.collection.immutable.Map[String,String] = Map(a -> a, b -> b, c -> c)
所以,显然它有效。这有什么区别?
附加说明:
在这里看起来像“for comprehension”的游戏规则:如果它产生了某些东西,那些东西必须与外部集合的类型相同(在这种情况下是authHeaders,这是一个选项[?] )。如何解决它?
谢谢! 拉嘎
答案 0 :(得分:8)
问题
你的for
被玷污了:
authHeaders.flatMap(headers => headers.map(header => header -> header))
本例中的问题是使用flatMap
,因为authHeaders
是Option
。
让我们来看看签名。 (http://www.scala-lang.org/api/2.11.1/index.html#scala.Option)
final def flatMap[B](f: (A) ⇒ Option[B]): Option[B]
因此,函数f
应返回Option
。但authHeaders.map(header => header -> header)
不是Option
,因此您会收到错误。
解决方案
假设如果authHeaders
为None
,您想要一个空的Map
,我们可以使用fold
。
authHeaders.fold(Map.empty[String, String])(_.map(s => s -> s).toMap)
如果authHeaders
为None
,则第一个参数是结果。第二个应该是一个函数Set[String] => Map[String, String]
,如果有Set
,则会对其进行评估。
如果您希望将结果保留在Option
中,并且只想在实际存在Map
时获得Set
,则可以使用map
。
authHeaders.map(_.map(s => s -> s).toMap)
关于您的附加说明
这是flatMap
上TraversableOnce
的签名。 (http://www.scala-lang.org/api/2.11.1/index.html#scala.collection.TraversableOnce)
def flatMap[B](f: (A) ⇒ GenTraversableOnce[B]): TraversableOnce[B]
此处f
可以返回任何GenTraversableOnce
实例的集合。
所以这样的事情是可能的:Set(1,2,3).flatMap(i => List(i))
(不是真正的创意例子,我知道......)
我认为Option
是一个特例。