3 回答
TA贡献1829条经验 获得超6个赞
我同意推断“唯一可能的”类型会很好,即使调用是链接在一起的,但存在技术限制。
您可以将推理视为对表达式的广度优先扫描,收集对类型变量的约束(由子类型边界和必需的隐式参数引起),然后求解这些约束。这种方法允许例如隐式指导类型推断。在您的示例中,即使仅查看xs.toSet
子表达式也有一个解决方案,但是以后的链接调用可能会引入使系统无法满足的约束。保留类型变量未解决的缺点是,对闭包的类型推断需要知道目标类型,因此将失败(它需要做一些具体的事情-所需的闭包类型及其参数类型必须并非两者都是未知的)。
现在,当延迟解决约束使推理失败时,我们可以回溯,解决所有类型变量,然后重试,但是实现起来很棘手(可能效率很低)。
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编译器没有做到这一点。
- 3 回答
- 0 关注
- 440 浏览
添加回答
举报