在Scala中键入推断和类型边界

时间:2015-07-23 22:52:54

标签: scala generics type-inference type-bounds

考虑以下课程:

class Type { def +(other:Type):Type = this}
class SubType extends Type

现在我想创建一个包装器对象,该对象采用在Type或其派生类型上运行的二进制函数,让我们从:

开始
case class Fct(f:(Type,Type) => Type)

我可以使用Fct apply方法实例化_+_类,但我无法使用Subtype类传递函数,这是预期的:

val f1 = Fct(_+_) // OK
val f2 = Fct((x:SubType,y:Type) => y) // error: found: (SubType, Type) => Type, required: (Type, Type) => Type

现在我们可以使用泛型定义Fct并输入bounds来接受子类型:

case class Fct[T <: Type, U <: Type, V <: Type](f:(T,U) => V)

现在f2按预期工作,但f1已无效,我不明白为什么:

val f1 = Fct(_+_)  // error: missing parameter type
val f2 = Fct((x:SubType,y:Type) => y) // OK

是否有接受f1f2的语法?

修改

(回复m-z)有没有办法解决工厂的差异问题?类似的东西:

class Fct(f:(Type,Type) => Type)
object Fct {
  def apply(f:(Type,Type) => Type): Fct = new Fct(f)
  def apply[T <: Type, U <: Type, V <: Type](f:(T,U) => V): Fct =
    new Fct((x:Type,y:Type) => {(x,y) match {
      case (a:T, b:U) => f(a,b)
      case _ => ???
    }}: Type)
}

1 个答案:

答案 0 :(得分:4)

Fct((x: SubType, y: Type) => y)的问题不是语法,而是方差。 f中的Fct类型为(Type, Type) => Type,即Function2[Type, Type, Type]Function2在前两个类型参数上是逆变的。

这意味着(SubType, Type) => Type 不是 (Type, Type) => Type的子类型。因此,您无法使用它代替(Type, Type) => Type。请注意,Fct((x: Type, y: Type) => y)工作正常。

使用Fct的通用版本,当您编写Fct(_+_)时,无法推断类型TU。在这种情况下,你可以期望的最好的是:

Fct[SubType, Type, Type](_ + _)

简而言之,第一种方法可以正常工作,但是你的函数参数类型被固定到Type(或者你可能不想要的超类型)。这可能没问题,因为您仍然可以将SubType作为参数传递给该函数,您只需将参数限制为SubType而不会破坏Function2的逆变。第二种方法只有在某处 注释类型时才有效。