用于理解可选的集合迭代和产量
For comprehension with optional collection iteration and yield
我不是很精通 Scala,并且真诚地发现文档很难尝试解决这个问题,但我想知道是否有人可以向我解释为什么以下语句的编译存在差异:
我可以轻松地遍历一组字符串并生成元素。
scala> for(name <- Set("asd", "123")) yield name
val res2: scala.collection.immutable.Set[String] = Set(asd, 123)
但是如果 Set 在 Option 中,我就不能内联了
scala> for(names <- Some(Set("asd", "123")); name <- names) yield (name)
^
error: type mismatch;
found : scala.collection.immutable.Set[String]
required: Option[?]
这是因为 for-yield
只是 flatMap
、map
和 withFilter
函数的语法糖。所以,你的代码:
for(names <- Some(Set("asd", "123")); name <- names) yield (name)
实际上是一样的:
Some(Set("asd", "123")).flatMap{ names: Set[String] =>
names.flatMap{ name: String =>
name // return type is String, but Set[(of some )B] is expected
}
}// return type is Set[String] but Option[(of some) C] is expected
查看Option
flatMap
函数:
@inline final def flatMap[B](f: A => Option[B]): Option[B]
但是你的f
returnsSet[String]
因此,编译器告诉您类型不匹配 (Set[String] != Option[?]
):
error: type mismatch;
found : scala.collection.immutable.Set[String]
required: Option[?]
你应该记住 for-yield
构造中第一个语句的类型。在您的情况下,它是 names <- Some(Set("asd", "123"))
。它的类型为 Option[Set[String]]
,所以你应该只在 x <- yourNextStatement
行中使用 Option[T]
(x
应该有 Option[T]
类型)。
总结:
在 for-yield
结构中混合使用不同的容器类型时要小心。如果您遇到一些问题,请尝试将 for-yield
解包为 flatMap
、map
、withFilter
函数的组合。
如果你想在for-yeild
中混合容器,你应该为每个-容器类型启动另一个for-yield .例如:
for {
names <- Some(Set("asd", "123"))
// will return Option[String]
reducedNames <- (for {
name <- names // here will be used Seq flatMap function, not Option
} yield (name + "some_suffix"))
.reduceLeftOption(_ + _) // here we will get Option[String] from Seq[String]
} yield reducedNames // will return Option[String]
你希望 None
发生什么?假设“无”,你可以做
val optionalSet = Some(Set("asd", "123"))
for (names <- optionalSet.getOrElse(Set.empty); name <- names) yield name
我不是很精通 Scala,并且真诚地发现文档很难尝试解决这个问题,但我想知道是否有人可以向我解释为什么以下语句的编译存在差异:
我可以轻松地遍历一组字符串并生成元素。
scala> for(name <- Set("asd", "123")) yield name
val res2: scala.collection.immutable.Set[String] = Set(asd, 123)
但是如果 Set 在 Option 中,我就不能内联了
scala> for(names <- Some(Set("asd", "123")); name <- names) yield (name)
^
error: type mismatch;
found : scala.collection.immutable.Set[String]
required: Option[?]
这是因为 for-yield
只是 flatMap
、map
和 withFilter
函数的语法糖。所以,你的代码:
for(names <- Some(Set("asd", "123")); name <- names) yield (name)
实际上是一样的:
Some(Set("asd", "123")).flatMap{ names: Set[String] =>
names.flatMap{ name: String =>
name // return type is String, but Set[(of some )B] is expected
}
}// return type is Set[String] but Option[(of some) C] is expected
查看Option
flatMap
函数:
@inline final def flatMap[B](f: A => Option[B]): Option[B]
但是你的f
returnsSet[String]
因此,编译器告诉您类型不匹配 (Set[String] != Option[?]
):
error: type mismatch;
found : scala.collection.immutable.Set[String]
required: Option[?]
你应该记住 for-yield
构造中第一个语句的类型。在您的情况下,它是 names <- Some(Set("asd", "123"))
。它的类型为 Option[Set[String]]
,所以你应该只在 x <- yourNextStatement
行中使用 Option[T]
(x
应该有 Option[T]
类型)。
总结:
在 for-yield
结构中混合使用不同的容器类型时要小心。如果您遇到一些问题,请尝试将 for-yield
解包为 flatMap
、map
、withFilter
函数的组合。
如果你想在for-yeild
中混合容器,你应该为每个-容器类型启动另一个for-yield .例如:
for {
names <- Some(Set("asd", "123"))
// will return Option[String]
reducedNames <- (for {
name <- names // here will be used Seq flatMap function, not Option
} yield (name + "some_suffix"))
.reduceLeftOption(_ + _) // here we will get Option[String] from Seq[String]
} yield reducedNames // will return Option[String]
你希望 None
发生什么?假设“无”,你可以做
val optionalSet = Some(Set("asd", "123"))
for (names <- optionalSet.getOrElse(Set.empty); name <- names) yield name