这个问题出现在我正在编写的模块中,但我做了一个表现出相同行为的最小案例。
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_|
来简化这一过程。
实际错误:
推断类型参数[Nothing,Minimal [Int]]不符合方法apply的类型参数bounds [T,X&lt;:Sugar.S [T]]
答案 0 :(得分:9)
这不是Scala编译器错误,但它肯定是Scala类型推断的限制。在解决X
之前,编译器想要确定S[T]
,X
上的绑定,但是绑定提到了迄今为止无约束的类型变量T
,它因此修复了Nothing
{1}}从那里开始。一旦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
desugars to,
def apply[T, X](x : X)(implicit conv : X => S[T]) = x.doSomething
现在可以独立解决类型变量T
和X
(因为T
的约束中不再提及X
。这意味着X
立即被推断为Minimal
,并且T
作为隐式搜索类型X => S[T]
的值的一部分来解决,以满足隐式参数{ {1}}。 conv
中的conforms
生成此表单的值,并且在上下文中将保证给定类型scala.Predef
的参数,Minimal
将被推断为Int。您可以在Scala中将其视为functional dependencies的实例。
答案 1 :(得分:4)
结构类型的边界有些奇怪,尝试使用S [T]上的视图绑定。
def apply[T, X <% S[T]] (x: X) = x.doSomething
效果很好。