Scala 中 Covarient/Contravarient 注释的用例
Use cases of Covarient/Contravarient Annotations in Scala
在 Scala 中,可以通过以下方式指定函数或 class 是协变还是逆变
class Foo[+arg] // covarient
class Bar[-arg] // contravarient
此功能的实际用途是什么?
我知道编译器运行检查以确保声明的实体实际上是协变的或其他,但即使添加此类注释有什么好处?
最简单的情况是您可能已经在使用它而不知道它是 Scala 集合。
class A()
class B() extends A
case class Container[T](elem : T)
val listOfA:List[A] = List[B](new B(),new B())
val containerOfA:Container[A] = Container[B](new B()) // fails
假设您有以下层次结构:
class A
class B extends A
协方差。协变类型可以作为return类型:
class Foo[+arg] { // Covariant
def getArg(): arg = ???
}
def testCovariant(): Unit = {
val fooB = new Foo[B]
val foo: Foo[A] = fooB
// returns only objects of class derived from A
// so it is safe
val a: A = foo.getArg()
}
因此您可以使用 Foo[DerivedClass]
中的任何一个 Foo[BaseClass]
,因为任何 Foo[BaseClass].getArg
被调用的地方 BaseClass
都是预期的结果,任何 DerivedClass
可以 returned 并分配给它。
逆变。逆变类型可以作为方法参数类型:
class Bar[-arg] { // Contravariant
def setArg(p: arg): Unit = ???
}
def testContravariant(): Unit = {
val barA = new Bar[A]
val bar: Bar[B] = barA
// can set B to bar which is actually Bar[A]
// but Bar[A].setArg(p: A) can accept any object
// of type derived from A
// so it is safe
bar.setArg(new B)
}
再次。您可以在使用 Bar[BaseClass]
的地方使用 Bar[DerivedClass]
中的任何一个,因为任何 Bar[DerivedClass].setArg(p: DerivedClass)
被称为 DerivedClass
的地方都应该作为参数,并且任何 Bar[BaseClass]
都可以在此上下文中使用, 因为你总是可以将 DerivedClass
传递给 Bar[BaseClass].setArg(p: BaseClass)
.
在 Scala 中,可以通过以下方式指定函数或 class 是协变还是逆变
class Foo[+arg] // covarient
class Bar[-arg] // contravarient
此功能的实际用途是什么? 我知道编译器运行检查以确保声明的实体实际上是协变的或其他,但即使添加此类注释有什么好处?
最简单的情况是您可能已经在使用它而不知道它是 Scala 集合。
class A()
class B() extends A
case class Container[T](elem : T)
val listOfA:List[A] = List[B](new B(),new B())
val containerOfA:Container[A] = Container[B](new B()) // fails
假设您有以下层次结构:
class A
class B extends A
协方差。协变类型可以作为return类型:
class Foo[+arg] { // Covariant
def getArg(): arg = ???
}
def testCovariant(): Unit = {
val fooB = new Foo[B]
val foo: Foo[A] = fooB
// returns only objects of class derived from A
// so it is safe
val a: A = foo.getArg()
}
因此您可以使用 Foo[DerivedClass]
中的任何一个 Foo[BaseClass]
,因为任何 Foo[BaseClass].getArg
被调用的地方 BaseClass
都是预期的结果,任何 DerivedClass
可以 returned 并分配给它。
逆变。逆变类型可以作为方法参数类型:
class Bar[-arg] { // Contravariant
def setArg(p: arg): Unit = ???
}
def testContravariant(): Unit = {
val barA = new Bar[A]
val bar: Bar[B] = barA
// can set B to bar which is actually Bar[A]
// but Bar[A].setArg(p: A) can accept any object
// of type derived from A
// so it is safe
bar.setArg(new B)
}
再次。您可以在使用 Bar[BaseClass]
的地方使用 Bar[DerivedClass]
中的任何一个,因为任何 Bar[DerivedClass].setArg(p: DerivedClass)
被称为 DerivedClass
的地方都应该作为参数,并且任何 Bar[BaseClass]
都可以在此上下文中使用, 因为你总是可以将 DerivedClass
传递给 Bar[BaseClass].setArg(p: BaseClass)
.