The classic example is functions, taking the Scala interface for a function with a single argument:
trait Function1[-T1, +R]
Which is contravariant (the -
) for the argument, and covariant (the +
) for the return type.
Why?
Imagine you have these classes:
class Timelord { ... }
class Doctor extends Timelord { ... }
class Enemy { ... }
class Dalek extends Enemy { ... }
If you have a method that takes, as a parameter, a Doctor => Enemy
function; then it's okay to supply an instance of TimeLord => Enemy
. It'll still accept instances of Doctor
.
So TimeLord => Enemy
is a subclass of Doctor => Enemy
because TimeLord
is a superclass of Doctor
, it's contravariant in that parameter.
Likewise, a function returning a Dalek
is valid when you need a function returning some Enemy
, because a Dalek
is-an Enemy
So Doctor => Dalek
is a subclass of Doctor => Enemy
because Dalek
is a subclass of Enemy
, it's covariant in that parameter.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…