问题描述
我遇到这个问题,每次都必须解决.我无法使用for理解来映射Future包含的内容.
I have this issue that I have to work around every time. I can't map over something that is contained within a Future using a for comprehension.
示例:
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
val f = Future( List("A", "B", "C") )
for {
list <- f
e <- list
} yield (e -> 1)
这给了我错误:
error: type mismatch;
found : List[(String, Int)]
required: scala.concurrent.Future[?]
e <- list
^
但是,如果我这样做,它就可以正常工作:
But if I do this it works fine:
f.map( _.map( (_ -> 1) ) )
我应该不能通过使用for理解来做到这一点,这是它在我的另一个示例中可以不进行平面映射的原因吗?我正在使用Scala 2.10.0.
Should i not be able to do this by using a for comprehension, is the reason it works in my other example that I do not flatmap? I'm using Scala 2.10.0.
推荐答案
好吧,当您为了理解而在一个生成器中有多个生成器时,您正在展平生成的类型.也就是说,得到的不是List[List[T]]
,而是得到的List[T]
:
Well, when you have multiple generators in a single for comprehension, you are flattening the resulting type. That is, instead of getting a List[List[T]]
, you get a List[T]
:
scala> val list = List(1, 2, 3)
list: List[Int] = List(1, 2, 3)
scala> for (a <- list) yield for (b <- list) yield (a, b)
res0: List[List[(Int, Int)]] = List(List((1,1), (1,2), (1,3)), List((2,1
), (2,2), (2,3)), List((3,1), (3,2), (3,3)))
scala> for (a <- list; b <- list) yield (a, b)
res1: List[(Int, Int)] = List((1,1), (1,2), (1,3), (2,1), (2,2), (2,3),
(3,1), (3,2), (3,3))
现在,您将如何展平Future[List[T]]
?它不能是Future[T]
,因为您将获得多个T
,并且Future
(与List
相对)只能存储其中之一.顺便说一句,Option
也会发生相同的问题:
Now, how would you flatten a Future[List[T]]
? It can't be a Future[T]
, because you'll be getting multiple T
, and a Future
(as opposed to a List
) can only store one of them. The same problem happens with Option
, by the way:
scala> for (a <- Some(3); b <- list) yield (a, b)
<console>:9: error: type mismatch;
found : List[(Int, Int)]
required: Option[?]
for (a <- Some(3); b <- list) yield (a, b)
^
解决这个问题的最简单方法是简单地嵌套多个内容以进行理解:
The easiest way around it is to simply nest multiple for comprehensions:
scala> for {
| list <- f
| } yield for {
| e <- list
| } yield (e -> 1)
res3: scala.concurrent.Future[List[(String, Int)]] = scala.concurrent.im
pl.Promise$DefaultPromise@4f498585
回想起来,这种局限性应该是显而易见的.问题在于,几乎所有示例都使用集合,并且所有集合都只是GenTraversableOnce
,因此可以自由地混合它们.此外,Scala受到批评的CanBuildFrom
机制使得可以混入任意集合并返回特定类型,而不是GenTraversableOnce
.
In retrospect, this limitation should have been pretty obvious. The problem is that pretty much all examples use collections, and all collections are just GenTraversableOnce
, so they can be mixed freely. Add to that, the CanBuildFrom
mechanism for which Scala has been much criticized makes it possible to mix in arbitrary collections and get specific types back, instead of GenTraversableOnce
.
而且,为了使事情变得更加模糊,可以将Option
转换为Iterable
,只要不首先出现选项,就可以将选项与集合组合在一起.
And, to make things even more blurry, Option
can be converted into an Iterable
, which makes it possible to combine options with collections as long as the option doesn't come first.
但是,我认为困惑的主要根源是,在进行理解教学时,没有人提到这一局限性.
But the main source of confusion, in my opinion, is that no one ever mentions this limitation when teaching for comprehensions.
这篇关于无法用于理解以映射Future中的List的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!