类型不匹配在斯卡拉理解

为什么这个构造在Scala中导致类型不匹配错误?

for (first <- Some(1); second <- List(1,2,3)) yield (first,second)

<console>:6: error: type mismatch;
 found   : List[(Int, Int)]
 required: Option[?]
       for (first <- Some(1); second <- List(1,2,3)) yield (first,second)

如果我使用List切换Some,它编译得很好:

for (first <- List(1,2,3); second <- Some(1)) yield (first,second)
res41: List[(Int, Int)] = List((1,1), (2,1), (3,1))

这也很好:

for (first <- Some(1); second <- Some(2)) yield (first,second)

理解转换为对mapflatMap方法的调用。 例如这一个:

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方法调用。 由于List上的flatMap返回另一个List ,因此理解的结果当然是List 。 (这对我来说是新的:理解并不总是导致流,甚至不一定在Seq 。)

现在,看看如何在Option声明flatMap

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调用的参数是根据需要返回List ,但不是Option

为了解决这个问题,您可以执行以下操作:

for(x <- Some(1).toSeq ; y <- List(1,2,3)) yield (x, y)

这编译得很好。 值得注意的是, Option通常不是Seq的子类型。


一个简单的提示要记住,理解将尝试返回第一个生成器的集合的类型,在这种情况下选项[Int]。 所以,如果你从Some(1)开始,你应该期待Option [T]的结果。

如果你想得到List类型的结果,你应该从List生成器开始。

为什么有这个限制,而不是假设你总是想要某种顺序? 你可以有一种情况,它返回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的时候起作用? 在这种情况下,图书馆使用更通用的类型。 所以你可以将List和Traversable结合起来,并且有一个从Option到Traversable的隐式转换。

底线是这样的:考虑你希望表达式返回什么类型,并以该类型作为第一个生成器开始。 如有必要,将其包裹在该类型中。


这可能与Option不是可迭代的有关。 隐含的Option.option2Iterable将处理编译器期望第二个是可Option.option2Iterable的情况。 我期望编译器的魔力根据循环变量的类型而不同。

链接地址: http://www.djcxy.com/p/38013.html

上一篇: Type Mismatch on Scala For Comprehension

下一篇: Scala return type for tuple