我想在 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");}
^
答案 0 :(得分:5)
是的,这是正确的。由于Value
中的V
被定义为不变量,因此Value[Int]
和Value[String]
不是Value[Any]
的子类型,但Any
是最近的常见超类型Int
和String
,即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>
其中F
为Int
。
scala> val s_eqs = (cc : CC) => cc.s eqs "lol"
s_eqs: CC => Value[String] = <function1>
其中F
为String
。它适用于所有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}},您将失去很多类型检查。