前面带有加号的 scala 类型

Buf*_*lls 0 scala

sealed trait List[+A] // `List` data type, parameterized on a type, `A`
case object Nil extends List[Nothing] // A `List` data constructor representing the empty list
/* Another data constructor, representing nonempty lists. Note that `tail` is another `List[A]`,
which may be `Nil` or another `Cons`.
 */
case class Cons[+A](head: A, tail: List[A]) extends List[A]
Run Code Online (Sandbox Code Playgroud)

我的问题是A前面的“+”是什么?为什么在这里“List[A]”加号被忽略了?

谢谢

0__*_*0__ 6

类型构造函数参数前面的加号或减号表示该类型的值出现在协变 ( +) 或逆变 ( -) 位置。协变位置意味着该类型仅作为“输出”或返回类型出现,就像List. 然后,List[A]是的一个亚型List[B],如果A <: B,如果A是的子类型B

trait Animal { def food: String }
case class Dog(name: String) extends Animal { def food = "all" }

def test(xs: List[Animal]) = xs.map(_.food)

test(List(Dog("Jussi")))
Run Code Online (Sandbox Code Playgroud)

在这里你可以传递 a List[Dog]for aList[Animal]因为List[Dog] <: List[Animal]

逆变则相反——类型仅作为输入出现。例如Function1[A, Out] <: Function1[B, Out]if A >: B, ifA是 的超类型B

def test(fun: Dog => String): String = fun(Dog("Jussi"))

test { x: Animal => x.food }
Run Code Online (Sandbox Code Playgroud)

在这里你可以传递 a Animal => StringDog => String因为前者是后者的子类型。


变异注解+-只出现在类型的定义中,所以在 的定义中List[+A],而不是在其他任何地方List使用,例如作为类型归属或在extends子句中,因为变异一旦定义就不能改变。这称为定义站点差异。


因为Nothing是Scala 中的底层类型,是任何其他类型的子类型,因此我们可以方便地使用object Nil extends List[Nothing],从而Nil成为List[A]任何可能的的子类型A。无论何时需要列表,无论元素类型是什么,都可以使用Nil.