4
如果我的名字有关斯卡拉的最讨厌的事情,这将是为下面的代码:泛型类型和类型参数的Scala类型推断 - 为什么它不起作用?
trait G[+T]
class H[+T] extends G[T]
def f[A<:G[X], X<:Int](g :A)
val g :H[Int]
f(g)
编译器推断类型F中的最后一次通话[H [INT],没什么]和在我面前抱怨自己的愚蠢。
但是知道scala,它实际上比我知道得更清楚。它背后的原因是什么?由于G和H对于T来说是协变的,所以对于任何类型S来说都是S <: G[X] with H[_] <=> S<: H[X]
。这一缺点使我设计了一切,避免明确地指定类型 - 它可能看起来像什么都没有,但是当名称变成'真实'长度和几乎任何方法都是泛型的,并且通常在两个泛型类型上工作,事实证明,大多数代码都是类型声明。
编辑: 上面的情况是由诺亚解决的,但是当派生类与基类不同,如下所示?
trait G[+X]
class H[+X, Y] extends G[X]
class F extends G[Int]
def f[A<:G[X], X<:Int](g :A) = g
val h: H[Int, String] = ???
val g :F = ???
f(g)
f(h)
谢谢,它有一定的帮助,看起来像在这里circumvenes问题。但是,如果H是另一种类型,它将无济于事 - 需要更多的类型参数或没有,从而实例化G的参数。或者如果H在其参数上引入界限。所以我仍然对如果上述不起作用的理由感兴趣。 – Turin
你必须给出另一个不起作用的例子,我敢肯定,你通常可以让编译器同意你的看法。上面发生的事情是,编译器无法从'g:A'中提取类型。它可以发现'A'是'H [Int]',但即使你说'A <:G [X]',你也没有指定'X',所以它会成为barf。在我给出的例子中,指定了类型'X',以便编译器可以推断它。 – Noah
增加了解释更实际案例的代码。 – Turin