通用类型及其类型参数的 Scala 类型推断 - 为什么它不起作用?
Scala type inference for both a generic type and it's type parameter - why doesn't it work?
如果我要说出关于 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], Nothing] 的类型,并在我面前抱怨它自己的愚蠢。
虽然懂scala,但它居然比我懂。背后的原因是什么?由于 G 和 H 都是关于 T 的协变,S <: G[X] with H[_] <=> S<: H[X]
对于任何类型 S。这个缺点让我设计了一切,避免必须明确指定类型 - 它在这里看起来什么都没有,但是当名称变成 'real' 长度和几乎所有方法都是泛型的,而且经常处理两种泛型类型,事实证明大部分代码都是类型声明。
编辑:
上面的情况在下面由 Noah 解决了,但是当派生 class 与基础 class 不是同一类时会怎样,如下所示?
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)
如果你让 A
接受一个类型参数 A[_]
我想你可以让 Scala 编译器同意你的意见,而不是只做所有事情 Nothing
:
def f[A[_] <: G[_], X <: Int](g: A[X])
作为旁注,每当我遇到类型问题时,我通常会查看 scalaz
源代码,因为他们通常会遇到并尽可能地解决它。
更新
我上面提供的方法仍然适用于给定的附加约束:
trait G[+X]
class H[+X, Y] extends G[X]
class F extends G[Int]
class I extends G[String]
def f[A[_] <: G[_], X <: Int](g: A[X]) = g
val h: H[Int, String] = new H[Int, String]
val g: F = new F
val i:I = new I
f(g) //works
f(h) //works
f(i) // should fail and does fail
如果我要说出关于 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], Nothing] 的类型,并在我面前抱怨它自己的愚蠢。
虽然懂scala,但它居然比我懂。背后的原因是什么?由于 G 和 H 都是关于 T 的协变,S <: G[X] with H[_] <=> S<: H[X]
对于任何类型 S。这个缺点让我设计了一切,避免必须明确指定类型 - 它在这里看起来什么都没有,但是当名称变成 'real' 长度和几乎所有方法都是泛型的,而且经常处理两种泛型类型,事实证明大部分代码都是类型声明。
编辑: 上面的情况在下面由 Noah 解决了,但是当派生 class 与基础 class 不是同一类时会怎样,如下所示?
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)
如果你让 A
接受一个类型参数 A[_]
我想你可以让 Scala 编译器同意你的意见,而不是只做所有事情 Nothing
:
def f[A[_] <: G[_], X <: Int](g: A[X])
作为旁注,每当我遇到类型问题时,我通常会查看 scalaz
源代码,因为他们通常会遇到并尽可能地解决它。
更新
我上面提供的方法仍然适用于给定的附加约束:
trait G[+X]
class H[+X, Y] extends G[X]
class F extends G[Int]
class I extends G[String]
def f[A[_] <: G[_], X <: Int](g: A[X]) = g
val h: H[Int, String] = new H[Int, String]
val g: F = new F
val i:I = new I
f(g) //works
f(h) //works
f(i) // should fail and does fail