일반적으로 공변량 유형 매개 변수는 클래스가 하위 유형화됨에 따라 범위가 변경 될 수있는 유형입니다 (또는 하위 유형에 따라 달라 지므로 "co-"접두어). 보다 구체적으로 :
trait List[+A]
List[Int]의 하위 유형 List[AnyVal]이기 때문에 Int의 하위 유형입니다 AnyVal. 이는 List[Int]유형 값 List[AnyVal]이 예상 되는 인스턴스를 제공 할 수 있음을 의미합니다 . 이것은 제네릭이 작동하는 데 매우 직관적 인 방법이지만 변경 가능한 데이터가있을 때 소리가 나지 않습니다 (유형 시스템이 깨짐). 이것이 제네릭이 Java에서 변하지 않는 이유입니다. Java 배열을 사용하는 소리가 들리지 않는 간단한 예 (공변이 잘못됨) :
Object[] arr = new Integer[1];
arr[0] = "Hello, there!";
우리는 방금 유형의 값을 할당했습니다. String 의 배열에Integer[] . 명백한 이유 때문에 이것은 나쁜 소식입니다. Java 타입 시스템은 실제로 컴파일 타임에 이것을 허용합니다. JVM은 "유용하게" ArrayStoreException런타임에 던질 것이다 . 스칼라의 타입 시스템은 Array클래스 의 타입 매개 변수 가 변하지 않기 때문에이 문제를 방지합니다 (선언이 [A]아닌 [+A]).
반공 분산으로 알려진 다른 유형의 분산이 있습니다. . 공분산으로 인해 일부 문제가 발생할 수있는 이유를 설명하므로 매우 중요합니다. 공분산은 말 그대로 공분산의 반대입니다. 매개 변수 는 하위 유형에 따라 위쪽 으로 다양 합니다. 매우 직관적 인 응용 프로그램이 있기는하지만 반 직관적이기 때문에 부분적으로 덜 일반적입니다.
trait Function1[-P, +R] {
def apply(p: P): R
}
type 매개 변수 에 " - "분산 주석이 P있습니다. Function1전체적으로이 선언 은P 공변량 및 공변량을R . 따라서 다음과 같은 공리를 도출 할 수 있습니다.
T1' <: T1
T2 <: T2'
---------------------------------------- S-Fun
Function1[T1, T2] <: Function1[T1', T2']
공지 사항 T1'의 하위 유형 (또는 같은 종류)해야합니다T1 그것이 대한 반대 인 반면에, T2그리고 T2'. 영어로 다음과 같이 읽을 수 있습니다.
함수 A는 다른 기능의 하위 유형 B 의 파라미터를 입력하면 , A는 의 파라미터 형태의 슈퍼이고 B가 의 반환 입력 중 A는 의 리턴 타입의 서브 타입 인 B .
이 규칙의 이유는 독자에게 연습으로 남겨두고 있습니다 (힌트 : 위의 배열 예제와 같이 함수가 하위 유형으로 지정되므로 다른 경우에 대해 생각하십시오).
공분산 및 반공 분산에 대한 새로운 지식을 통해 다음 예제가 컴파일되지 않는 이유를 확인할 수 있습니다.
trait List[+A] {
def cons(hd: A): List[A]
}
문제는 A공변량이지만 cons함수는 유형 매개 변수가 변하지 않을 것으로 예상합니다. . 따라서 A잘못된 방향으로 변화하고 있습니다. 흥미롭게도, 우리는에 List반 변형 을 만들어서이 문제를 해결할 수는 A있지만 List[A], cons함수가 리턴 타입이 공변 인 을 기대하기 때문에 리턴 타입 은 유효하지 않습니다 .
여기서 우리의 유일한 두 가지 옵션은 a) A불변을 만들고 공분산의 훌륭하고 직관적 인 하위 입력 속성을 잃거나 b) 하한으로 cons정의 A되는 메서드에 지역 유형 매개 변수를 추가하는 것입니다 .
def cons[B >: A](v: B): List[B]
이제 유효합니다. 당신은 그것을 상상할 수 있습니다A 아래로B 수 있지만,AA 그것의 하한 이기 때문에 . 이 메소드 선언으로A 공변량을 수 있으며 모든 것이 잘 작동합니다.
이 트릭 List은 덜 구체적인 유형에 특화된 인스턴스를 반환하는 경우에만 작동합니다 B. List변경 가능 하게 만들 려고하면 type 값을 type B변수에 할당하려고 시도하기 때문에 문제 A가 발생합니다. 이는 컴파일러에서 허용하지 않습니다. 변경 가능성이있을 때마다 (종종 접근 자와 함께) 불변성을 암시하는 특정 유형의 메소드 매개 변수가 필요한 일종의 뮤 테이터가 필요합니다. 공분산은 변경 불가능한 데이터와 함께 작동합니다. 가능한 유일한 조작은 접근 자이므로 공변량 리턴 유형이 제공 될 수 있습니다.
var동안 설정 가능val하지 않습니다. 스칼라의 불변 컬렉션이 공변량이지만 변이 가능한 컬렉션이 아닌 이유도 마찬가지입니다.