문제
나는 다음과 같은 작업을 수행 해야하는 스칼라 코드를 작성하려고합니다.
class Test[Type] {
def main {
SomeFunc classOf[Type]
val testVal: Type = new Type()
}
}
그리고 실패합니다. 나는 분명히 Scala Generic 매개 변수에 대해 이해하지 못합니다. 분명히, 오해는 C ++에서 템플릿이 본질적으로 문자열 대체와 같은 기능을 수행하므로 전달되는 클래스에 기본 생성자가있는 한 New Type ()가 작동한다는 것입니다. 그러나 스칼라에서는 유형이 다른 종류의 물체입니다.
해결책
지적한 바와 같이, C ++에는 템플릿이 있습니다. 요컨대, C ++는 "테스트가 컴파일하는 모든 유형 T에 대한 테스트가 있습니다"라고 말합니다. 따라서 T에 제약 조건을 쉽게 추가 할 수 있지만 다운쪽에는 암시 적이며 코드를 읽지 않고도 클래스 사용자가 이해하기 어려울 수 있습니다.
Scala의 파라 메트릭 다형성 (일명 제네릭)은 ML, Haskell, Java 및 C#과 훨씬 비슷합니다. Scala에서 "Class Test [T]를 쓸 때 "모든 T에 대해"제약없이 유형 테스트가 있습니다 "라고 말합니다. 그것은 공식적으로 추론하기가 더 간단하지만, 그것은 당신이 제약에 대해 명시해야한다는 것을 의미합니다. 예를 들어, 스칼라에서 "클래스 테스트 [t <: foo]는 t가 foo의 하위 유형이어야한다고 말할 수 있습니다.
C#은 생성자와 관련하여 T에 제약 조건을 추가하는 방법이 있지만 불행히도 Scala는 그렇지 않습니다.
스칼라에서 문제를 해결하는 몇 가지 방법이 있습니다. 하나는 TypeSafe이지만 BT는 더 장점입니다. 다른 하나는 TypeSafe가 아닙니다.
TypeSafe 방식은 모양입니다
class Test[T](implicit val factory : () => T) {
val testVal = factory
}
그런 다음 시스템에 유용한 유형에 대한 공장을 가질 수 있습니다.
object Factories {
implicit def listfact[X]() = List[X]()
implicit def setfact[X]() = Set[X]()
// etc
}
import Factories._
val t = new Test[Set[String]]
도서관 사용자가 자신의 공장이 필요한 경우 공장 대상과 동등한 자체를 추가 할 수 있습니다. 이 솔루션의 장점 중 하나는 공장이없는 모든 것이 사용될 수 있다는 것입니다.
Not-So-Typesafe Way는 반사와 Scala의 특징을 사용하여 유형 삭제에 관한 Java 제약을 얻는 방법입니다.
class Test[T](implicit m : Manifest[T]) {
val testVal = m.erasure.newInstance().asInstanceOf[T]
}
이 버전을 사용하면 여전히 씁니다
class Foo
val t = new Test[Foo]
그러나 사용 가능한 ARG 생성자가 없으면 정적 유형 오류 대신 런타임 예외가 발생합니다.
scala> new Test[Set[String]]
java.lang.InstantiationException: scala.collection.immutable.Set
at java.lang.Class.newInstance0(Class.java:340)