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

为什么类型推断在这里失败?


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.toSet

res42: 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)


慕丝7291255
浏览 449回答 3
3回答

肥皂起泡泡

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

ITMISS

类型推断无法正常工作,因为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&nbsp; &nbsp;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编译器没有做到这一点。
打开App,查看更多内容
随时随地看视频慕课网APP