왜 예제가 컴파일되지 않는가, 일명 (공동, 콘트라, 및 비) 분산은 어떻게 작동하지 않습니까?

StackOverflow https://stackoverflow.com/questions/663254

문제

후속 이 질문, 누군가 스칼라에서 다음을 설명 할 수 있습니까?

class Slot[+T] (var some: T) { 
   //  DOES NOT COMPILE 
   //  "COVARIANT parameter in CONTRAVARIANT position"

}

나는의 차이점을 이해합니다 +T 그리고 T 유형 선언에서 (사용하는 경우 컴파일됩니다. T). 그러나 실제로 물건을 만드는 데 의지하지 않고 유형 매개 변수에 공분산이있는 수업을 실제로 작성하는 방법 비교되지 않은? 다음과 같은 인스턴스로 만 다음을 생성 할 수 있는지 확인하십시오. T?

class Slot[+T] (var some: Object){    
  def get() = { some.asInstanceOf[T] }
}

편집하다 - 이제 이것을 다음으로 내려 놓았습니다.

abstract class _Slot[+T, V <: T] (var some: V) {
    def getT() = { some }
}

이것은 모두 좋지만 이제는 하나만 원합니다. 다음과 같이 질문을 다시 해제하겠습니다.

어떻게 쓸 수 있습니까? 불변 Slot 수업입니다 공분산 그 유형에서?

편집 2: Duh! 나는 사용했다 var 그리고 아닙니다 val. 다음은 내가 원하는 것입니다.

class Slot[+T] (val some: T) { 
}
도움이 되었습니까?

해결책

일반적으로 a 공분산 유형 매개 변수는 클래스가 하위 유형이므로 변동 할 수있는 파라미터입니다 (또는 하위 유형에 따라 다르므로 "코"접두사). 더 구체적으로 :

trait List[+A]

List[Int] 하위 유형입니다 List[AnyVal] 왜냐하면 Int 하위 유형입니다 AnyVal. 이것은 당신이 인스턴스를 제공 할 수 있음을 의미합니다 List[Int] 유형 값이있을 때 List[AnyVal] 예상됩니다. 이것은 제네릭이 작동하는 매우 직관적 인 방법이지만, 변이 가능한 데이터가있을 때 사용될 때는 불분명하다 (유형 시스템을 중단)한다는 것이 밝혀졌다. 이것이 바로 제네릭이 자바에서 변하지 않는 이유입니다. Java 어레이를 사용한 건전도의 간단한 예 (잘못된 공분산) :

Object[] arr = new Integer[1];
arr[0] = "Hello, there!";

방금 유형 값을 할당했습니다 String 유형의 배열로 Integer[]. 명백 해야하는 이유로, 이것은 나쁜 소식입니다. Java의 유형 시스템은 실제로 컴파일 시간에이를 허용합니다. JVM은 "유용하게"던질 것입니다 ArrayStoreException 런타임에. Scala의 유형 시스템은이 문제를 방지합니다. Array 클래스는 변하지 않습니다 (선언은입니다 [A] 보다는 [+A]).

다음으로 알려진 다른 유형의 분산이 있습니다. 비밀. 이는 공분산이 몇 가지 문제를 일으킬 수있는 이유를 설명하기 때문에 매우 중요합니다. 말 그대로 공분산의 반대입니다. 매개 변수는 다양합니다. 상승 하위 유형으로. 그것은 매우 중요한 응용 프로그램 인 기능이 있지만, 반 직관적이기 때문에 부분적으로는 부분적으로 훨씬 덜 일반적입니다.

trait Function1[-P, +R] {
  def apply(p: P): R
}

"-"분산 주석 P 유형 매개 변수. 이 선언은 전체적으로 그것을 의미합니다 Function1 비밀리에 있습니다 P 그리고 공분산 R. 따라서 우리는 다음 공리를 도출 할 수 있습니다.

T1' <: T1
T2 <: T2'
---------------------------------------- S-Fun
Function1[T1, T2] <: Function1[T1', T2']

그것을주의해라 T1' 하위 유형 (또는 동일한 유형)이어야합니다. T1, 반대입니다 T2 그리고 T2'. 영어로는 다음과 같이 읽을 수 있습니다.

기능 다른 함수의 하위 유형입니다 매개 변수 유형 인 경우 매개 변수 유형의 슈퍼 타입입니다 반환 유형의 동안 리턴 유형의 하위 유형입니다 .

이 규칙의 이유는 독자에게 연습으로 남아 있습니다 (힌트 : 위의 배열 예와 같이 함수가 하위 유형이기 때문에 다른 경우에 대해 생각하십시오).

새로운 공동 및 분열에 대한 지식을 통해 다음 예제가 왜 컴파일되지 않는지 확인할 수 있어야합니다.

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 변동성, 결국 유형 값을 할당하려고했기 때문에 상황이 무너집니다. B 변수 유형으로 A, 컴파일러가 허용하지 않습니다. 돌연변이가있을 때마다 어떤 종류의 돌연변이터가 있어야하는데, 이는 특정 유형의 메소드 매개 변수가 필요하며 (액세서와 함께) 불변성을 의미합니다. 공분산은 불변 데이터와 함께 작동합니다. 가능한 유일한 작업은 액세서리이기 때문에 공분산 반환 유형이 제공 될 수 있습니다.

다른 팁

@Daniel은 그것을 아주 잘 설명했습니다. 그러나 허용 된 경우 간단히 설명하기 위해 다음과 같이 설명합니다.

  class Slot[+T](var some: T) {
    def get: T = some   
  }

  val slot: Slot[Dog] = new Slot[Dog](new Dog)   
  val slot2: Slot[Animal] = slot  //because of co-variance 
  slot2.some = new Animal   //legal as some is a var
  slot.get ??

slot.get 그런 다음 런타임에 오류가 발생하여 변환하는 데 실패했습니다. Animal 에게 Dog (Duh!).

일반적으로 돌연변이 성은 공동 분위기 및 대조 분산과 잘 어울리지 않습니다. 그것이 모든 Java 컬렉션이 변하지 않는 이유입니다.

보다 예제 별 스칼라, 57 페이지+ 이에 대한 전체 논의.

내가 당신의 의견을 올바르게 이해하고 있다면, 당신은 56 페이지의 하단에서 시작하는 구절을 다시 읽어야합니다 (기본적으로, 당신이 요구하는 것은 실행 시간 검사없이 유형 안전하지 않다고 생각합니다. Scala는하지 않습니다. 그래서 당신은 운이 좋지 않습니다). 구조물을 사용하도록 예제를 번역하십시오.

val x = new Slot[String]("test") // Make a slot
val y: Slot[Any] = x             // Ok, 'cause String is a subtype of Any
y.set(new Rational(1, 2))        // Works, but now x.get() will blow up 

내가 당신의 질문 (뚜렷한 가능성)을 이해하지 못한다고 생각한다면 문제 설명에 더 많은 설명 / 컨텍스트를 추가하면 다시 시도하겠습니다.

편집에 대한 응답으로 : 불변의 슬롯은 완전히 다른 상황입니다 ... * 미소 * 위의 예가 도움이 되었기를 바랍니다.

매개 변수에 하한을 적용해야합니다. 구문을 기억하는 데 어려움을 겪고 있지만 다음과 같이 보일 것이라고 생각합니다.

class Slot[+T, V <: T](var some: V) {
  //blah
}

Scala-by example은 이해하기가 약간 어렵고 몇 가지 구체적인 예가 도움이되었을 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top