混合通用类型
Mixing generic types
我想在我的 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");}
^
是的,没错。因为Value
在V
中被定义为不变的,这意味着Value[Int]
和Value[String]
不是Value[Any]
的子类型,但是Any
是Int
和 String
的最接近的公共超类型,即 myTest
中的 F
。因为V
是在协变的位置,所以可以简单修改为:
case class Value[+V](value: V)
不是协方差而是存在类型。在你的函数中
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
的参数是“CC => Value[F]
的某种类型 F
的列表,它可能与列表中的另一个参数不同. 究竟哪些是存在类型 :) 长版本可能更清楚:
scala> def myTest(values: (CC ⇒ Value[F] forSome { type F } )*) = Unit
myTest: (values: CC => Value[_]*)Unit.type
添加的 forSome { type F }
声明存在一个 F
,其参数类型为 CC => Value[F]
,但 "forget" 关于 F
。因此 Value[Int]
变为 Value[F]
未知 F
并且 Value[String]
也是如此。从外面看,它们都变成了同一类型,所以它起作用了。这种语法虽然非常清晰,但大多数时候可以通过下划线缩短:
scala> def myTest(values: (CC ⇒ Value[_])*) = Unit
myTest: (values: CC => Value[_]*)Unit.type
像这样重新定义 myTest
:
def myTest(values: CC => Value[_]*) = Unit
这样,传递给 myTest
的每个函数对象都会有一个适合 Value
的类型参数,它 returns.
如果您使用协方差(例如 Value[+V]
),您不妨将 Value
替换为 Any
,因为 Scala 编译器将提供 Any
作为推断类型对于 myTest[F]
中的 F
,您将失去很多类型检查。
我想在我的 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");}
^
是的,没错。因为Value
在V
中被定义为不变的,这意味着Value[Int]
和Value[String]
不是Value[Any]
的子类型,但是Any
是Int
和 String
的最接近的公共超类型,即 myTest
中的 F
。因为V
是在协变的位置,所以可以简单修改为:
case class Value[+V](value: V)
不是协方差而是存在类型。在你的函数中
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
的参数是“CC => Value[F]
的某种类型 F
的列表,它可能与列表中的另一个参数不同. 究竟哪些是存在类型 :) 长版本可能更清楚:
scala> def myTest(values: (CC ⇒ Value[F] forSome { type F } )*) = Unit
myTest: (values: CC => Value[_]*)Unit.type
添加的 forSome { type F }
声明存在一个 F
,其参数类型为 CC => Value[F]
,但 "forget" 关于 F
。因此 Value[Int]
变为 Value[F]
未知 F
并且 Value[String]
也是如此。从外面看,它们都变成了同一类型,所以它起作用了。这种语法虽然非常清晰,但大多数时候可以通过下划线缩短:
scala> def myTest(values: (CC ⇒ Value[_])*) = Unit
myTest: (values: CC => Value[_]*)Unit.type
像这样重新定义 myTest
:
def myTest(values: CC => Value[_]*) = Unit
这样,传递给 myTest
的每个函数对象都会有一个适合 Value
的类型参数,它 returns.
如果您使用协方差(例如 Value[+V]
),您不妨将 Value
替换为 Any
,因为 Scala 编译器将提供 Any
作为推断类型对于 myTest[F]
中的 F
,您将失去很多类型检查。