首页 文章

为什么Scala在嵌套类型参数时不能完全推断类型参数?

提问于
浏览
13

请考虑以下Scala代码:

abstract class A
abstract class B[T <: A]
class ConcreteA extends A
class ConcreteB extends B[ConcreteA]

class Example[U <: B[T], T <: A]( resolver: U )
object Test {
    new Example( new ConcreteB )
}

最后一行 new Example( new ConcreteB ) 无法编译,并出现以下错误:

错误:推断类型参数[ConcreteB,Nothing]不符合类Example的类型参数bounds [U <:B [T],T <:A]

ConcreteB 拥有解决U和T的所有必要数据 . 我在这里缺少什么?

3 回答

  • 10

    基普顿与他的高级解决方案接近 . 不幸的是,他绊倒了Scala <2.9.1.RC1中的一个错误 . 以下工作与2.9.1.RC1和trunk一样,

    Welcome to Scala version 2.9.1.RC1 (Java HotSpot(TM) Server VM, Java 1.7.0).
    Type in expressions to have them evaluated.
    Type :help for more information.
    
    scala> abstract class A
    defined class A
    
    scala> abstract class B[T <: A]
    defined class B
    
    scala> class ConcreteA extends A
    defined class ConcreteA
    
    scala> class ConcreteB[T <: A] extends B[T]
    defined class ConcreteB
    
    scala> class Example[T <: A, U[X <: A] <: B[X]](resolver: U[T])
    defined class Example
    
    scala> new Example(new ConcreteB[ConcreteA])
    res0: Example[ConcreteA,ConcreteB] = Example@ec48e7
    
  • 10

    (另见两个相关问题:Scala fails to infer the right type argumentsType infered to Nothing in Scala

    它看起来像是Scala的限制's type inference, which is intentionally not spec' ed . 作为解决方法,您可以通过使 T 成为 B 的类型成员而不是参数来进行推理,

    abstract class A
    abstract class B { type T <: A }
    class ConcreteA extends A
    class ConcreteB extends B { type T = ConcreteA }
    class Example[U <: B]( resolver: U )
    object Test {
        new Example( new ConcreteB )
    }
    

    当使用类型成员时,'s useful to know that they can be surfaced as type parameters using refinement, as in Miles Sabin' s回答:Why is this cyclic reference with a type projection illegal?

    在Jean-Philippe Pellet对a related question的回答中,通过使类型参数更高的类型来辅助类型推断 . 如果在 ConcreteB 中引入了一个额外的类型参数,那么类型推断可以工作,

    abstract class A
    abstract class B[T <: A]
    class ConcreteA extends A
    class ConcreteB[T <: A] extends B[T]
    class Example[T <: A, U[T0 <: A] <: B[T0]]( resolver: U[T] )
    object Test {
      new Example( new ConcreteB[ConcreteA] )
    }
    

    Scala 2.9给出了下面的神秘错误消息,但Miles Sabin指出这是一个将修复为2.9.1的错误

    <console>:15: error: kinds of the type arguments (ConcreteA,ConcreteB[T0]) do not conform to the expected kinds of the type parameters (type T,type U) in class Example.
    ConcreteB[T0]'s type parameters do not match type U's expected parameters: class ConcreteB has one type parameter, but type U has one
             new Example( new ConcreteB[ConcreteA] )
                 ^
    
  • 2

    为了自己的学习,我在GitHub上创作了a document of type inference workarounds .

    我发现一些有用的简单规则是:

    • Type parameters of type parameters cannot be inferred: Scala类型推断仅查看参数列表中指定的类型(不要与类型参数列表混淆) .

    • Previous parameters are not used to infer future parameters: 类型信息仅流经参数列表,而不是参数 .


    但是,在这个特定的例子中,类型成员是前进的方向(感谢@Kipton Barros!)

相关问题