为了账号安全,请及时绑定邮箱和手机立即绑定

Scala上的类型不匹配以进行理解

Scala上的类型不匹配以进行理解

墨色风雨 2019-11-12 14:49:21
为什么这种构造会在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)如果我用列表切换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)
查看完整描述

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通常所假定的的子类型。


查看完整回答
反对 回复 2019-11-12
?
慕尼黑8549860

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的隐式转换。


底线是:考虑要让表达式返回哪种类型,并以该类型作为第一个生成器开始。如有必要,将其包装为该类型。


查看完整回答
反对 回复 2019-11-12
  • 3 回答
  • 0 关注
  • 558 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信