考虑以下课程:
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
是否有接受f1
和f2
的语法?
修改
(回复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)
}
答案 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(_+_)
时,无法推断类型T
和U
。在这种情况下,你可以期望的最好的是:
Fct[SubType, Type, Type](_ + _)
简而言之,第一种方法可以正常工作,但是你的函数参数类型被固定到Type
(或者你可能不想要的超类型)。这可能没问题,因为您仍然可以将SubType
作为参数传递给该函数,您只需将参数限制为SubType
而不会破坏Function2
的逆变。第二种方法只有在某处 注释类型时才有效。