这个问题出现在我正在编写的模块中,但我做了一个表现出相同行为的最小案例.
class Minimal[T](x : T) { def doSomething = x } object Sugar { type S[T] = { def doSomething : T } def apply[T,X <: S[T]] (x: X) = x.doSomething } object Error { val a = new Minimal(4) Sugar(a) // error: inferred [nothing,Minimal[Int]] does not fit the bounds of apply Sugar[Int,Minimal[Int]](a) // works as expected }
问题是编译器设法找出Minimal(Int)的内部参数,但是然后将T的另一个出现设置为nothing,这显然与apply不匹配.这些肯定是相同的T,因为删除第一个参数使第二个抱怨T未定义.
是否有一些含糊不清意味着编译器无法推断出第一个参数,或者这是一个错误?我可以优雅地解决这个问题吗?
更多信息:此代码是尝试语法糖的简单示例.原始代码尝试制作|(a)|表示a的模数,其中a是矢量.显然|(a)|比写[| Float,Vector3 [Float]](a)|更好,但不幸的是我不能使用unary_ |使这更容易.
实际错误:
inferred type arguments [nothing,Minimal[Int]] do not conform to method apply’s type parameter bounds [T,X <: Sugar.S[T]]
解决方法
这不是Scala编译器错误,但它肯定是Scala类型推断的限制.在解决X之前,编译器想要确定X,S [T]上的边界,但是绑定提到了迄今为止无约束的类型变量T,因此它固定在nothing并从那里继续.一旦X完全解析,它就不会重新审视T …在这种情况下,当前类型推断总是从左到右进行.
如果您的示例准确地表示您的实际情况,那么有一个简单的修复,
def apply[T](x : S[T]) = x.doSomething
这里将推断T,使得Minimal直接符合S [T]而不是通过中间有界类型变量.
更新
约书亚的解决方案也避免了推断类型T的问题,但是以完全不同的方式.
def apply[T,X <% S[T]](x : X) = x.doSomething
desugars,
def apply[T,X](x : X)(implicit conv : X => S[T]) = x.doSomething
现在可以独立地求解类型变量T和X(因为在X的界限中不再提及T).这意味着X立即被推断为Minimal,并且T被解析为隐式搜索类型X =>的值的一部分. S [T]满足隐式参数conv. scala中的conform.Predef制造这种形式的值,并且在上下文中将保证给定Minimal类型的参数,T将被推断为Int.您可以在Scala中将其视为functional dependencies的实例.