这个问题的灵感来自this one。在下面的示例中,为什么使用表达式的预期类型和隐式参数的组合会导致类型推断器确定函数的类型参数不约束隐式参数? (如果这就是这里实际发生的事情。)
case class ThingA(name: String)
case class ThingB(name: String)
class ThingClass[T]
implicit val thingClassA = new ThingClass[ThingA]
implicit val thingClassB = new ThingClass[ThingB]
def find[T](): Option[T] = None
def findWithContextBound[T: ThingClass](): Option[T] = None
val typeApplicationFind = find[ThingA]()
val typeApplicationFindWithContextBound = findWithContextBound[ThingA]()
val expectedTypeFind: Option[ThingA] = find()
val expectedTypeFindWithContextBound: Option[ThingA] = findWithContextBound()
只有最后一个表达式是不明确的,即使期望的类型应该约束findWithContextBound的类型参数。
答案 0 :(得分:3)
在推断类型参数之前发生隐式解析。在最后一行中,当编译器搜索隐式T
时,type参数仍然是未解析的ThingClass
,因此thingClassA
和thingClassB
都可以接受,因此编译器因模糊的隐式值错误而失败。
为什么Scala以这种方式工作?它允许类型参数,因此返回类型,由可用的含义决定。其中一个用途是映射BitSet
:
import collection.immutable.BitSet
val bitSet = BitSet(1, 2)
// another BitSet:
val newBitSet = bitSet.map(_ + 1)
// BitSet can't hold String, so this is a SortedSet:
val notABitSet = bitSet.map(_.toString)
BitSet
只能容纳Int
个实例。 BitSet.map
采用隐式CanBuildFrom
来指示是否可以从起始集合构建特定结果集合,同时还包含映射的结果。当CanBuildFrom
函数的返回类型为BitSet
时,有一个map
允许映射到另一个Int
,并且有一个更通用的隐式创建{{1}无论返回类型如何。第一个是优先选择的,但编译器会在需要时回退到第二个。