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

使用.toSet生成的Set上的类型推断失败?

使用.toSet生成的Set上的类型推断失败?

慕丝7291255 2019-11-19 14:28:08
为什么类型推断在这里失败?scala> val xs = List(1, 2, 3, 3)xs: List[Int] = List(1, 2, 3, 3)scala> xs.toSet map(_*2)<console>:9: error: missing parameter type for expanded function ((x$1) => x$1.$times(2))       xs.toSet map(_*2)但是,如果xs.toSet已分配,它将进行编译。scala> xs.toSetres42: scala.collection.immutable.Set[Int] = Set(1, 2, 3)scala> res42 map (_*2)res43: scala.collection.immutable.Set[Int] = Set(2, 4, 6)同样,采用另一种方法,Set从转换为List,并映射为List。scala> Set(5, 6, 7)res44: scala.collection.immutable.Set[Int] = Set(5, 6, 7)scala> res44.toList map(_*2)res45: List[Int] = List(10, 12, 14)
查看完整描述

3 回答

?
肥皂起泡泡

TA贡献1829条经验 获得超6个赞

我同意推断“唯一可能的”类型会很好,即使调用是链接在一起的,但存在技术限制。

您可以将推理视为对表达式的广度优先扫描,收集对类型变量的约束(由子类型边界和必需的隐式参数引起),然后求解这些约束。这种方法允许例如隐式指导类型推断。在您的示例中,即使仅查看xs.toSet子表达式也有一个解决方案,但是以后的链接调用可能会引入使系统无法满足的约束。保留类型变量未解决的缺点是,对闭包的类型推断需要知道目标类型,因此将失败(它需要做一些具体的事情-所需的闭包类型及其参数类型必须并非两者都是未知的)。

现在,当延迟解决约束使推理失败时,我们可以回溯,解决所有类型变量,然后重试,但是实现起来很棘手(可能效率很低)。


查看完整回答
反对 回复 2019-11-19
?
ITMISS

TA贡献1871条经验 获得超8个赞

类型推断无法正常工作,因为List#toSetis 的签名


def toSet[B >: A] => scala.collection.immutable.Set[B]

并且编译器需要在调用中的两个位置推断类型。在函数中注释参数的另一种方法是toSet使用显式类型参数进行调用:


xs.toSet[Int] map (_*2)

更新:


关于您的问题,为什么编译器可以分两步进行推断,让我们看一下一一行地输入行时会发生什么:


scala> val xs = List(1,2,3)

xs: List[Int] = List(1, 2, 3)


scala> val ys = xs.toSet   

ys: scala.collection.immutable.Set[Int] = Set(1, 2, 3)

在这里,编译器会推断出最具体类型,ys这是Set[Int]在这种情况下。现在已经知道这种类型,因此map可以推断传递给函数的类型。


如果在示例中填写了所有可能的类型参数,则调用将写为:


xs.toSet[Int].map[Int,Set[Int]](_*2)

第二个type参数用于指定返回的集合的类型(有关详细信息,请查看Scala集合的实现方式)。这意味着我什至低估了编译器必须推断的类型数量。


在这种情况下,似乎很容易推断出来,Int但在某些情况下却并非如此(鉴于Scala的其他功能,例如隐式转换,单例类型,混合的特性等)。我并不是说这无法完成-只是Scala编译器没有做到这一点。


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

添加回答

举报

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