Scala 协变类型FParam出现在值猜测的类型Seq[FParam]中的逆变位置
考虑这个简单的例子:Scala 协变类型FParam出现在值猜测的类型Seq[FParam]中的逆变位置,scala,covariance,contravariance,scala-generics,Scala,Covariance,Contravariance,Scala Generics,考虑这个简单的例子: trait Optimizer[+FParam, FRes] { def optimize( fn: (FParam) => FRes, guesses: Seq[FParam] // <--- error ) } 逆变类型出现在type(FParam)=>FRes 同样,同样的悖论:在Function1[-T1,R]中,第一个类型参数显然是反变的,那么为什么FParam处于协变位置呢?(问题2) 如中所述,我可以通过翻转差异来解决此问
trait Optimizer[+FParam, FRes] {
def optimize(
fn: (FParam) => FRes,
guesses: Seq[FParam] // <--- error
)
}
逆变类型出现在type(FParam)=>FRes
同样,同样的悖论:在Function1[-T1,R]
中,第一个类型参数显然是反变的,那么为什么FParam
处于协变位置呢?(问题2)
如中所述,我可以通过翻转差异来解决此问题,但不清楚为什么需要这样做
trait Optimizer[+FParam, FRes] {
type U <: FParam
def optimize(
fn: (FParam) => FRes,
guesses: Seq[U]
)
}
trait优化器[+FParam,FRes]{
U型壁画,
猜测:Seq[U]
)
}
问题在于FParam没有直接使用。它位于optimize
的参数中,因此其方差被翻转。为了举例说明,让我们看看optimize
的类型(请参见val optim
):
trait优化器[+FParam,FRes]{
U型壁画,
猜测:Seq[U]
)
val optim:Function2[
功能1[
FParam,
壁画
],
序号[U],
单位
]=优化
}
问题在于FParam没有直接使用。它位于optimize
的参数中,因此其方差被翻转。为了举例说明,让我们看看optimize
的类型(请参见val optim
):
trait优化器[+FParam,FRes]{
U型壁画,
猜测:Seq[U]
)
val optim:Function2[
功能1[
FParam,
壁画
],
序号[U],
单位
]=优化
}
问题1:+FParam
表示协变类型FParam
,它从超类型到子类型FParam
。对于猜测
它期望协变类型
用于Seq
。因此,您可以为此显式声明FPParam
的超类型,如:
def optimize[B >: FParam](fn: (B) => FRes, guesses: Seq[B]) // B is the super type of FParam
或者像这样
那么为什么猜测
它期望共变异类型
为序列
?例如:
trait Animal
case class Dog() extends Animal
case class Cat() extends Animal
val o = new Optimizer2[Dog, Any]
val f: Dog => Any = (d: Dog) => ...
o.optimize(f, List(Dog(), Cat())) // if we don't bind B in `guesses` for supertype of `FParam`, it will fail in compile time, since the `guesses` it's expecting a `Dog` type, not the `Animal` type. when we bind it to the supertype of `Dog`, the compiler will infer it to `Animal` type, so `cotravariant type` for `Animal`, the `Cat` type is also matched.
问题2:-FParam
指的是cotravairant类型FParam
,它从超类型FParam
到它的子类型。对于fn:Function1[-T1,+R]/(FParam)=>FRes
它期望的是协变类型。因此,您可以通过反转问题1类型状态来完成,如:
def optimize[B <: FParam](fn: (B) => FRes, guesses: Seq[B]) // B is the sub type of FParam
def optimize[B FRes,guesses:Seq[B])//B是FParam的子类型
问题1:+FParam
表示协变类型FParam
,它从超类型到子类型FParam
。对于猜测
,它期望序列
的协变类型
。因此,您可以通过明确声明一个超类为此键入FPParam
,如:
def optimize[B >: FParam](fn: (B) => FRes, guesses: Seq[B]) // B is the super type of FParam
或者像这样
那么为什么猜测
对于序列
,它期望的是协变量类型
?例如:
trait Animal
case class Dog() extends Animal
case class Cat() extends Animal
val o = new Optimizer2[Dog, Any]
val f: Dog => Any = (d: Dog) => ...
o.optimize(f, List(Dog(), Cat())) // if we don't bind B in `guesses` for supertype of `FParam`, it will fail in compile time, since the `guesses` it's expecting a `Dog` type, not the `Animal` type. when we bind it to the supertype of `Dog`, the compiler will infer it to `Animal` type, so `cotravariant type` for `Animal`, the `Cat` type is also matched.
问题2:-FParam
指的是COTRAVARIANT类型FParam
,它从超类型FParam
到其子类型。对于fn:Function1[-T1,+R]/(FParam)=>FRes
这是一个协变的类型。所以你可以通过倒转问题1的类型状态来实现,比如:
def optimize[B <: FParam](fn: (B) => FRes, guesses: Seq[B]) // B is the sub type of FParam
def optimize[B FRes,guesses:Seq[B])//B是FParam的子类型
希望我能消除这种困惑
Seq[]不是列表,并且其中不能同时包含多个类类型。您的特征优化器具有未知但固定的类FParam或子类,但您的函数返回Seq[FParam]不绑定为与封闭对象相同的子类。因此,可能会导致运行时中不同的子类同时出现在Seq[FParam]中,因此整个代码块成为Scala编译错误
abstract class Optimizer[+FParam, FRes] {
}
object Optimizer{
def optimize[FParam,FRes](obj: Optimizer[FParam,FRes], param : FParam) : (FParam,Seq[FParam]) = (param,(Nil))
}
trait(现在是一个抽象类)仍然有协方差泛型参数,但是在其参数中使用协方差泛型的函数被类型锁定为具有不变量的确切类型-强制在函数中使用相同的类或子类,现在在单例对象中。希望我能够消除混淆
Seq[]不是列表,并且其中不能同时包含多个类类型。您的特征优化器具有未知但固定的类FParam或子类,但您的函数返回Seq[FParam]不绑定为与封闭对象相同的子类。因此,可能会导致运行时中不同的子类同时出现在Seq[FParam]中,因此整个代码块成为Scala编译错误
abstract class Optimizer[+FParam, FRes] {
}
object Optimizer{
def optimize[FParam,FRes](obj: Optimizer[FParam,FRes], param : FParam) : (FParam,Seq[FParam]) = (param,(Nil))
}
trait(现在是一个抽象类)仍然具有协变泛型参数,但是在其参数中使用协变泛型的函数被类型锁定为具有不变量的确切类型-强制的,该不变量与现在在singleton对象中的函数中的同一类或子类相同