【问题标题】:Scala type inference for both a generic type and it's type parameter - why doesn't it work?Scala 对泛型类型及其类型参数的类型推断 - 为什么它不起作用?
【发布时间】:2015-09-11 03:51:04
【问题描述】:

如果我要说出关于 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 &lt;: G[X] with H[_] &lt;=&gt; S&lt;: H[X] 对于任何类型 S。这个缺点使我设计一切都避免必须明确指定类型 - 它在这里可能看起来什么都没有,但是当名称变为“真实”时长度和几乎任何方法都是泛型的,并且经常处理两种泛型类型,结果大部分代码都是类型声明。

编辑: 上面的情况在下面被Noah解决了,但是当派生类和基类不一样时怎么办,如下?

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)

【问题讨论】:

    标签: scala generics type-inference type-parameter higher-kinded-types


    【解决方案1】:

    如果你让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
    

    【讨论】:

    • 谢谢,它确实很有帮助,看起来它绕过了这里的问题。但是,如果 H 属于不同的类型,这将无济于事 - 需要更多类型参数或没有,实例化 G 的参数。或者,如果 H 在其参数上引入了界限。所以我仍然对上述方法不起作用的原因感兴趣。
    • 你必须再举一个例子说明什么是行不通的,我很确定你通常可以让编译器同意你的看法。上面发生的情况是编译器无法从g:A 中提取类型。它可以计算出AH[Int],但你没有指定X,所以即使你说A &lt;: G[X],它也会出错。在我给出的示例中,指定了类型X,以便编译器可以推断它。
    • @Turin 我提供的方法适用于您添加的新案例
    • 哇,谢谢!我想在某个时候有一个大的重构在等着我,我会看看它是否能解决我所有的实际问题。
    猜你喜欢
    • 1970-01-01
    • 2014-02-04
    • 1970-01-01
    • 1970-01-01
    • 2023-03-05
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多