这个问题出现在我正在编写的模块中,但是我做了一个最小的案例,表现出相同的行为。
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_|
来简化此操作。实际错误:
最佳答案
这不是Scala编译器的错误,但肯定是Scala类型推断的局限性。编译器希望在求解X
之前确定S[T]
,X
的界限,但是界限提到了迄今为止不受约束的类型变量T
,因此它固定在Nothing
并从那里开始。一旦T
已完全解决,它就不会重新访问X
…目前,在这种情况下,类型推断总是从左向右进行。
如果您的示例准确地代表了您的实际情况,那么有一个简单的解决方法,
def apply[T](x : S[T]) = x.doSomething
在这里,将推断
T
,以便Minimal
直接符合S[T]
而不是通过中介的有界类型变量。更新
Joshua的解决方案还避免了推断类型
T
的问题,但采用了完全不同的方式。def apply[T, X <% S[T]](x : X) = x.doSomething
对...不满意
def apply[T, X](x : X)(implicit conv : X => S[T]) = x.doSomething
现在可以独立地解决类型变量
T
和X
的问题(因为T
的绑定(bind)中不再提到X
)。这意味着X
立即被推断为Minimal
,并且T
作为隐式搜索的一部分来求解X => S[T]
类型的值,以满足隐式参数conv
。 conforms
中的scala.Predef
会制造这种形式的值,并且在上下文中将保证给定Minimal
类型的参数时,T
将被推断为Int。您可以在Scala中将其视为functional dependencies的实例。关于scala - 为什么输入推断在这里不起作用?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10343244/