3 回答
TA贡献1793条经验 获得超6个赞
对于理解将转换为对mapor flatMap方法的调用。例如这个:
for(x <- List(1) ; y <- List(1,2,3)) yield (x,y)
变成:
List(1).flatMap(x => List(1,2,3).map(y => (x,y)))
因此,第一个循环值(在本例中为List(1))将接收flatMap方法调用。由于flatMap在List返回另一个List,的的理解,结果当然会是一个List。(这对我来说是新的:因为理解并不总是导致信息流,甚至不一定会导致Seqs。)
现在,看看如何flatMap在中声明Option:
def flatMap [B] (f: (A) ⇒ Option[B]) : Option[B]
请记住这一点。让我们看看如何将理解错误(带有的错误Some(1))转换为一系列map调用:
Some(1).flatMap(x => List(1,2,3).map(y => (x, y)))
现在,很容易看到该flatMap调用的参数是按要求返回a List而不是返回的东西Option。
为了解决问题,您可以执行以下操作:
for(x <- Some(1).toSeq ; y <- List(1,2,3)) yield (x, y)
这样编译就可以了。值得注意的是,Option它不是Seq通常所假定的的子类型。
TA贡献1818条经验 获得超11个赞
一个容易记住的技巧,因为理解会尝试返回第一个生成器的集合类型,在这种情况下为Option [Int]。因此,如果从Some(1)开始,则应该期望Option [T]的结果。
如果要获取列表类型的结果,则应从列表生成器开始。
为什么有此限制,而不假定您总是需要某种顺序?您可能会遇到需要返回的情况Option。也许你有一个Option[Int]你想要的东西结合起来,得到一个Option[List[Int]],用下面的函数说:(i:Int) => if (i > 0) List.range(0, i) else None; 然后,您可以编写此代码,并在事情没有“意义”时得到None:
val f = (i:Int) => if (i > 0) Some(List.range(0, i)) else None
for (i <- Some(5); j <- f(i)) yield j
// returns: Option[List[Int]] = Some(List(0, 1, 2, 3, 4))
for (i <- None; j <- f(i)) yield j
// returns: Option[List[Int]] = None
for (i <- Some(-3); j <- f(i)) yield j
// returns: Option[List[Int]] = None
实际上,如何扩展理解力实际上是将类型的对象M[T]与函数组合(T) => M[U]以获得类型的对象的相当通用的机制M[U]。在您的示例中,M可以是Option或List。通常,它必须是相同的类型M。因此,您不能将Option与List结合使用。有关可能存在的其他情况的示例M,请查看此特征的子类。
为什么结合List[T]与(T) => Option[T]工作虽然当你开始与列表?在这种情况下,库在有意义的地方使用更通用的类型。因此,您可以将List与Traversable结合使用,并且存在从Option到Traversable的隐式转换。
底线是:考虑要让表达式返回哪种类型,并以该类型作为第一个生成器开始。如有必要,将其包装为该类型。
- 3 回答
- 0 关注
- 584 浏览
添加回答
举报