混合泛型类型

时间:2015-08-12 09:08:25

标签: scala types covariance

我想在 myTest

中混合泛型类型
case class CC(i:Int, s:String, s2:String)

case class Value[V](value: V)

def myTest[F](values: (CC ⇒ Value[F])*) = Unit

class QF[M](x: M) {
  def eqs(v: M) = Value(x)
}

implicit def conversion[V](v: V): QF[V] = new QF(v)

myTest(_.i eqs 1)
myTest(_.s eqs "lol")
myTest(_.s eqs "lol", _.s2 eqs "lol2")

直到那时它才起作用,但我认为当我尝试混合类型时,我得到了协方差错误。

当我这样做时:

myTest(_.i eqs 1, _.s eqs "lol")

我收到以下错误:

Error:(16, 13) type mismatch;
 found   : A$A135.this.CC => A$A135.this.Value[Int]
 required: A$A135.this.CC => A$A135.this.Value[Any]
myTest(_.i eqs 1, _.s eqs "lol");}
           ^

3 个答案:

答案 0 :(得分:5)

是的,这是正确的。由于Value中的V被定义为不变量,因此Value[Int]Value[String]不是Value[Any]的子类型,但Any是最近的常见超类型IntString,即F中的myTest。由于V 处于协变位置,您可以简单地修改一下:

case class Value[+V](value: V)

答案 1 :(得分:2)

不是共同变异而是存在类型。在你的功能

def myTest[F](values: (CC ⇒ Value[F])*) = Unit

F可能会因调用myTest而异,但会在参数列表(CC ⇒ Value[F])*中修复。示例中的参数类型为

scala> val i_eqs = (cc : CC) => cc.i eqs 1
i_eqs: CC => Value[Int] = <function1>

其中FInt

scala> val s_eqs = (cc : CC) => cc.s eqs "lol"
s_eqs: CC => Value[String] = <function1>

其中FString。它适用于所有3个示例,因为F对于参数列表中的所有元素都是相同的。但是当你打电话时

myTest(_.i eqs 1, _.s eqs "lol")

编译器尝试将CC => Value[Int](第一个参数的类型)统一为CC => Value[String](第二个参数),这将简化为Value[Int]Value[String]的统一。实际上,您可以将Value定义为协变,这可能是一个好主意。但我想你真正想要的是表达myTest的参数是&#34;某些类型CC => Value[F]的{​​{1}}列表,它可能与参数不同在列表中。这究竟是存在类型:)长版本可能更清晰:

F

添加的scala> def myTest(values: (CC ⇒ Value[F] forSome { type F } )*) = Unit myTest: (values: CC => Value[_]*)Unit.type 表示存在forSome { type F },其参数的类型为F但是&#34;忘记&#34;关于CC => Value[F]。因此F对于未知Value[Int]变为Value[F]F也变为Value[String]。从外面看,它们都成为同一类型,因此它起作用。这种语法虽然非常明确,但大部分时间都可以通过下划线缩短:

scala> def myTest(values: (CC ⇒ Value[_])*) = Unit
myTest: (values: CC => Value[_]*)Unit.type

答案 2 :(得分:1)

像这样重新定义myTest

def myTest(values: CC => Value[_]*) = Unit

这样,传递给myTest的每个函数对象都会为它返回的Value提供合适的类型参数。

如果您使用协方差(例如Value[+V]),您也可以将Value替换为Any,因为Scala编译器将提供Any作为{的推断类型<{1}}中的{1}},您将失去很多类型检查。