일반적으로 공변량 유형 매개 변수는 클래스가 하위 유형화됨에 따라 범위가 변경 될 수있는 유형입니다 (또는 하위 유형에 따라 달라 지므로 "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
수 있지만,A
A
그것의 하한 이기 때문에 . 이 메소드 선언으로A
공변량을 수 있으며 모든 것이 잘 작동합니다.
이 트릭 List
은 덜 구체적인 유형에 특화된 인스턴스를 반환하는 경우에만 작동합니다 B
. List
변경 가능 하게 만들 려고하면 type 값을 type B
변수에 할당하려고 시도하기 때문에 문제 A
가 발생합니다. 이는 컴파일러에서 허용하지 않습니다. 변경 가능성이있을 때마다 (종종 접근 자와 함께) 불변성을 암시하는 특정 유형의 메소드 매개 변수가 필요한 일종의 뮤 테이터가 필요합니다. 공분산은 변경 불가능한 데이터와 함께 작동합니다. 가능한 유일한 조작은 접근 자이므로 공변량 리턴 유형이 제공 될 수 있습니다.
var
동안 설정 가능val
하지 않습니다. 스칼라의 불변 컬렉션이 공변량이지만 변이 가능한 컬렉션이 아닌 이유도 마찬가지입니다.