考虑这个简单的例子:
trait Optimizer[+FParam, FRes] {
def optimize(
fn: (FParam) => FRes,
guesses: Seq[FParam] // <--- error
)
}
它不编译,因为
协变类型
FParam
在值猜测的类型Seq[FParam]
中以逆变位置出现。
但是seq被定义为trait Seq[+A]
,那么这种逆变的来源是什么?(问题1(
相反,考虑这个简单的例子,-FParam
:
trait Optimizer[-FParam, FRes] {
def optimize(
fn: (FParam) => FRes, // <--- error
guesses: Seq[FParam]
)
}
逆变型在
(FParam) => FRes
型中以协变位置出现
同样,同样的悖论:在Function1[-T1, R]
中,第一个类型参数显然是逆变的,那么为什么FParam
处于协变位置呢?(问题2(
我可以通过翻转方差来解决此问题,如类型下限中所述,但为什么有必要尚不清楚。
trait Optimizer[+FParam, FRes] {
type U <: FParam
def optimize(
fn: (FParam) => FRes,
guesses: Seq[U]
)
}
问题 1:+FParam
表示协变类型FParam
,它因超型而异FParam
。 对于guesses
,它期望cotravariant type
Seq
。因此,您可以通过为此明确说明supertype
FPParam
来做到这一点,例如:
def optimize[B >: FParam](fn: (B) => FRes, guesses: Seq[B]) // B is the super type of FParam
或者像SeqViewLike一样。
那么为什么guesses
它期待Seq
cotravariant type
呢? 例如:
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
问题是 FParam 没有直接使用。它在optimize
的论证中,因此它的方差被颠倒了。为了说明,让我们看一下optimize
的类型(见val optim
(:
trait Optimizer[+FParam, FRes] {
type U <: FParam
def optimize(
fn: (FParam) => FRes,
guesses: Seq[U]
)
val optim: Function2[
Function1[
FParam,
FRes
],
Seq[U],
Unit
] = optimize
}
刚刚解决了这个问题,希望我能消除混乱。
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))
}
特征(现在是一个抽象类(仍然具有协变泛型参数,但在其参数中使用该协方差泛型的函数被类型锁定为具有不变的精确类型 - 强制要求函数中的相同类或子类现在在单例对象中。