为什么在 Scala 中定义子类型时不将协变设置为默认值?
Why not set covariant as default when define subtype in Scala?
表示定义trait Option[T]
等同于trait Option[+T]
。
很容易认为 val humanOpt: Option[Human]
可以指向一个 Option[Student]
实例,就像 val humanOpt: Human
可以指向一个 Student
实例一样。
也许这看起来有些奇怪,但为什么我会考虑这个?
Java变量默认为多态性,与c++相比,它应该使用virtual
keyword.I认为它是Java中简化OO的重要点。
Scala 在很多用例中使用高阶类型,比 Java 更频繁,例如 Option
、Try
或者我们自己定义一个 Cache[T]
。
此外,它仍然符合里氏替换原则。
我只想知道为什么不将协变简化为默认行为?
or define a Cache[T] by ourselves
如果你的 Cache
有一个 put(T)
方法,它不能是协变的,正是因为 Liskov 替换原则。
val humanCache: Cache[Human] = new Cache[Student] // legal if cache is covariant
humanCache.put(new Professor) // oops, we put a Professor into a Cache[Student]
所以让所有类型默认协变是行不通的。
您可以改用方差推理:如果类型可以是协变的,则使其协变;如果类型可以是逆变的,则使其为逆变;如果两者都不是,则使其不变。但是随后只需添加一个方法就可以改变方差并破坏大量使用您的类型的代码。通过明确显示所有差异,您在这样做时会被迫注意到。
表示定义trait Option[T]
等同于trait Option[+T]
。
很容易认为 val humanOpt: Option[Human]
可以指向一个 Option[Student]
实例,就像 val humanOpt: Human
可以指向一个 Student
实例一样。
也许这看起来有些奇怪,但为什么我会考虑这个?
Java变量默认为多态性,与c++相比,它应该使用virtual
keyword.I认为它是Java中简化OO的重要点。
Scala 在很多用例中使用高阶类型,比 Java 更频繁,例如 Option
、Try
或者我们自己定义一个 Cache[T]
。
此外,它仍然符合里氏替换原则。
我只想知道为什么不将协变简化为默认行为?
or define a Cache[T] by ourselves
如果你的 Cache
有一个 put(T)
方法,它不能是协变的,正是因为 Liskov 替换原则。
val humanCache: Cache[Human] = new Cache[Student] // legal if cache is covariant
humanCache.put(new Professor) // oops, we put a Professor into a Cache[Student]
所以让所有类型默认协变是行不通的。
您可以改用方差推理:如果类型可以是协变的,则使其协变;如果类型可以是逆变的,则使其为逆变;如果两者都不是,则使其不变。但是随后只需添加一个方法就可以改变方差并破坏大量使用您的类型的代码。通过明确显示所有差异,您在这样做时会被迫注意到。