수색…


공분산

+ 기호는 유형 매개 변수를 공변 (covariant) 으로 표시합니다. 여기서 " ProducerA 공변 (covariant)"이라고 말합니다.

trait Producer[+A] {
  def produce: A
}

공변 유형 매개 변수는 "출력"유형으로 생각할 수 있습니다. A 를 공변량으로 표시하면 Producer[X] <: Producer[Y]X <: Y 제공한다고 주장합니다. 예를 들어 Producer[Cat] 는 유효한 모든 생산 된 고양이가 유효한 동물이기 때문에 유효한 Producer[Animal] 입니다.

공변량 유형 매개 변수는 반공 변 (입력) 위치에 나타날 수 없습니다. 다음 예제는 우리가 Co[Cat] <: Co[Animal] 이지만 Co[Cat]def handle(a: Cat): Unit Co[Animal] 요구하는대로 Animal 을 처리 할 수없는 def handle(a: Cat): Unit 을 가지고 있다고 컴파일 할 때 컴파일되지 않습니다!

trait Co[+A] {
  def produce: A
  def handle(a: A): Unit
}

이 제한 사항을 처리하기위한 한 가지 접근법은 공변 유형 매개 변수로 묶인 유형 매개 변수를 사용하는 것입니다. 다음 예에서 BA 의 상위 유형임을 압니다. 따라서 주어진 Option[X] <: Option[Y] 에 대한 X <: Y , 우리가 알고 Option[X]def getOrElse[B >: X](b: => B): B 어떤 수퍼받을 수 X - Option[Y] 필요로하는 Y 의 수퍼 유형을 포함합니다.

trait Option[+A] {
  def getOrElse[B >: A](b: => B): B
}

불변성

기본적으로 모든 유형 매개 변수는 불변합니다. trait A[B] 주어지면 " AB 불변합니다"라고 말합니다. 이것은 A[Cat]A[Animal] 두 개의 매개 변수가 주어 졌음을 의미합니다. A[Cat] <: A[Animal] 또는 A[Cat] >: A[Animal] CatAnimal 사이의 관계에 관계없이 A[Cat] >: A[Animal] .

분산 주석은 이러한 관계를 선언하는 수단을 제공하고 형식 매개 변수의 사용에 규칙을 적용하여 관계가 유효하게 유지되도록합니다.

반공립

- 기호는 유형 매개 변수를 반항 문자로 표시합니다. 여기에서 " HandlerA 반역입니다"라고 말합니다.

trait Handler[-A] {
  def handle(a: A): Unit
}

contravariant type 매개 변수는 "입력"유형으로 생각할 수 있습니다. A 를 반 변형으로 표시하면 Handler[X] <: Handler[Y]X >: Y 제공한다고 주장합니다. 예를 들어 Handler[Animal] 는 유효한 Handler[Cat] 이며 Handler[Animal] 도 고양이를 처리해야합니다.

반 변형 유형 매개 변수는 공변 (출력) 위치에 나타날 수 없습니다. 다음 예제는 Contra[Animal] <: Contra[Cat] 주장하고 있으므로 컴파일되지 않습니다 Contra[Animal] <: Contra[Cat] 그러나 Contra[Animal] 에는 def produce: Animal Contra[Cat] 필요로하는 고양이를 생성 할 수없는 def produce: Animal !

trait Contra[-A] {
   def handle(a: A): Unit
   def produce: A
}

그러나 해상도 오버로드의 목적을 위해 contravariance는 contravariant type 매개 변수에서 유형의 특수성을 반 직관적으로 반전시킵니다. Handler[Animal]Handler[Cat] 보다 "더 구체적"인 것으로 간주됩니다.

형식 매개 변수에서 메서드를 오버로드 할 수 없으므로이 동작은 일반적으로 암시 적 인수를 해결할 때만 문제가됩니다. ofCat 의 반환 유형이 더 구체적 ofAnimal 의 다음 예제에서는 절대로 사용되지 않습니다.

implicit def ofAnimal: Handler[Animal] = ???
implicit def ofCat: Handler[Cat] = ???

implicitly[Handler[Cat]].handle(new Cat)

이 동작은 현재 scala.math.Ordering 으로 변경 될 예정이며 scala.math.Ordering 이 해당 유형 매개 변수 T 에 대해 변경되지 않는 이유는 (예를 들어) 한 가지 해결 방법은 typeclass를 불변으로 만들고 암시적인 정의를 해당 유형의 하위 클래스에 적용 할 이벤트에 입력 매개 변수로 설정하는 것입니다.

trait Person
object Person {
  implicit def ordering[A <: Person]: Ordering[A] = ???
}

콜렉션의 공분산

콜렉션은 일반적으로 요소 유형 *에서 공변 (covariant)이기 때문에 수퍼 유형이 예상되는 곳에서는 서브 유형 모음을 전달할 수 있습니다.

trait Animal { def name: String } 
case class Dog(name: String) extends Animal

object Animal {
  def printAnimalNames(animals: Seq[Animal]) = {
    animals.foreach(animal => println(animal.name))
  }
}

val myDogs: Seq[Dog] = Seq(Dog("Curly"), Dog("Larry"), Dog("Moe"))

Animal.printAnimalNames(myDogs)
// Curly
// Larry
// Moe

그것은 마법처럼 보인다, 그러나 사실 수 없습니다 Seq[Dog] 예상하는 방법으로 허용됩니다 Seq[Animal] : A (여기에 높은 kinded 유형의 전체 개념이다 Seq 의 형식 매개 변수에있는 공변).

* 반례는 표준 라이브러리의 집합입니다.

불변 식 특성에 대한 공분산

하나의 메소드가 전체 특성을 공변 (covariant)하는 대신 공변 인수 (covariant argument)를 허용하는 방법도 있습니다. 반역 위치에서 T 를 사용하기를 원하지만 여전히 공분산을 가지고 있기 때문에 이것은 필요할 수 있습니다.

trait LocalVariance[T]{
  /// ??? throws a NotImplementedError
  def produce: T = ???
  // the implicit evidence provided by the compiler confirms that S is a
  // subtype of T.
  def handle[S](s: S)(implicit evidence: S <:< T) = {
    // and we can use the evidence to convert s into t.
    val t: T = evidence(s)
    ???
  }
}

trait A {}
trait B extends A {}

object Test {
  val lv = new LocalVariance[A] {}

  // now we can pass a B instead of an A.
  lv.handle(new B {})
}


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow