이 문제는 매우 단순한 원인이 있으며 실제로는 분산과 관련이 없습니다. 더 간단한 예제를 고려해보십시오.
object Example {
def gimmeAListOf[T]: List[T] = List[Int](10)
}
이 스 니펫은 코드의 주요 아이디어를 포착합니다. 하지만 정확하지 않습니다.
val list = Example.gimmeAListOf[String]
list
의 유형은 무엇입니까? 메서드는 List[String]
에 대해 구체적으로 요청했지만 항상 List[Int](10)
을 반환합니다. 분명히 이것은 오류입니다. "을 당신은 내가 Example[T]
의 인스턴스를 반환합니다 줘 T
어떤 유형"이 방법은 정말 선언 method[T]: Example[T]
같은 서명이있는 경우
그래서 단어에 넣어합니다. 이러한 유형은 때로는 '보편적으로 정량화 된'또는 단순히 '보편적'이라고 불린다.
그러나 이것은 사용자의 경우가 아닙니다. 함수는 해당 매개 변수의 값에 따라 VehicleReader[T]
의 특정 인스턴스를 반환합니다. CarReader
(어느 것으로 추정 되나요? VehicleReader[Car]
). 내가 좋아하는 뭔가를 썼다 가정 : 컴파일러는 행복이 컴파일
class House extends Vehicle
val reader = VehicleReader[House](VehicleType.Car)
val house: House = reader.read() // Assuming there is a method VehicleReader[T].read(): T
을하지만,이 코드가 실행될 때 나는 ClassCastException
을 얻을 것이다.
두 가지 가능한 수정 방법이 있습니다.첫째, 당신은 자바 와일드 카드의보다 강력한 버전으로 생각 될 수있는 입력 존재 (또는 존재 적 정량)를 사용할 수 있습니다 :이 기능에 대한
def apply(vehicleType: VehicleType): VehicleReader[_] = ...
서명은 기본적으로 읽기
는 "당신이
VehicleType
나에게주고 내가 당신에게 돌아 일부 유형의 경우
VehicleReader
의 인스턴스입니다. 유형이 VehicleReader[_]
인 개체를 갖게됩니다. 이 유형이 존재한다는 것을 제외하고는 매개 변수의 유형에 대해 아무 것도 말할 수 없기 때문에 이러한 유형을 실존 적으로 호출합니다. def apply(vehicleType: VehicleType): VehicleReader[T] forSome {type T} = ...
이 동등한 정의하고 이러한 유형의 이러한 특성을 가지고 왜 아마 더 분명하다 - 당신이 그것에 대해 아무것도 모르는, 그래서 T
유형, 매개 변수의 내부에 숨겨져 있지만 존재 않습니다.
그러나 실존 정보의이 속성으로 인해 실제 유형 매개 변수에 대한 정보를 얻을 수 없습니다. 예를 들어 VehicleReader[Car]
이 을 벗어나는 경우/ClassTag
을 유형 매개 변수로 사용하여 VehicleReader
에 저장하고 캐스트하기 전에 확인하지 않는 한, 직접적인 캐스트 (asInstanceOf
)를 사용하는 경우는 예외입니다. 때때로 (실제로, 대부분의 경우) 다루기 힘들 때가 있습니다.
두 번째 옵션은 구조에 대한 것입니다.
VehicleType.Car -> CarReader (<: VehicleReader[Car])
VehicleType.Truck -> TruckReader (<: VehicleReader[Truck])
등 : 명확한 코드에서 VehicleType
와 VehicleReader[T]
간의 일치 성, 즉 당신이 VehicleType
의 특정 인스턴스가있을 때 당신은 확실히 콘크리트 T
VehicleReader[T]
에 서명을 알고있다.
이 때문에 유형 매개 변수를 VehicleType
에 추가하는 것이 좋습니다. 이 경우 귀하의 방법은 이제 입력 유형 및 출력 유형이 직접 연결되어
def apply[T <: Vehicle](vehicleType: VehicleType[T]): VehicleReader[T] = ...
처럼 보일 것이고,이 방법의 사용자는 자신이 원하는 것을 T
에 대한 VehicleType[T]
의 올바른 인스턴스를 제공하도록 강요 될 것이다. 이것은 이전에 언급 한 런타임 오류를 배제합니다. 그래도 asInstanceOf
캐스팅이 필요합니다.
sealed trait VehicleType[T <: Vehicle] {
def newReader: VehicleReader[T]
}
object VehicleType {
case object Car extends VehicleType[Car] {
def newReader = new CarReader
}
// ... and so on
}
을 다음 : 당신이 VehicleType[T]
형식 매개 변수의 실제 값을 알고있는 유일한 곳이 유형의 인스턴스가 구축되는 곳이기 때문에 완전히지지 않도록하려면, VehicleType
에 VehicleReader
인스턴스 코드 (예를 들어, 당신 new CarReader()
)를 이동해야합니다 VehicleReader
팩토리 메소드는 매우 깨끗보고 완전히 형태 보증 할 것이다 : 나는 또한 반환 형식의 자리를 시도했다
object VehicleReader {
def apply[T <: Vehicle](vehicleType: VehicleType[T]) = vehicleType.newReader
}
(즉 실존)하지만 다음주의로 캐스트 할 수 반환 값을 요구하는 결과 . 당신의 두 번째 제안을 탐구 할 것입니다. –
@ScalaNewb, 두 번째 접근법에 대해 자세히 설명했습니다. –