별명 내부 유형의 스칼라 케이스 클래스 매칭 컴파일 오류?
문제
별명 유형과 일치하는 케이스 클래스를 어떻게 사용합니까? 이것은 CB 등을 컨테이너에서 꺼낼 때 작동합니다.
class DoStuff[TKey](
val c : Container[TKey]#CB
)
{
type CB = Container[TKey]#CB
type C1 = Container[TKey]#C1
type C2 = Container[TKey]#C2
c match {
case C1(e1) => e1 // - not found: value e1 - not found: value C1
case C2(e2) => e2 // - not found: value e2 - not found: value C2
}
}
trait Container[TKey]
{
abstract trait CB
case class C1(val e : AnyRef) extends CB
case class C2(val e : AnyRef) extends CB
}
감사!
해결책
맞습니다 ... 스칼라의 내부 클래스는 약간 어리 석습니다. 제공 한 코드의 재 작성 버전을 표시하기 전에 간단한 예제를 시도해 봅시다.
case class Foo(x: Int) {
case class Bar(y: String)
}
이제 다음 코드 스 니펫을 고려하십시오.
val x = new Foo(1)
val y = new Foo(2)
val a = new x.Bar("one")
val b = new y.Bar("two")
가장 일반적인 유형 a
그리고 b
~이다 Foo#Bar
, 이는 내부 클래스를 의미합니다 Bar
유형의 외부 객체가 있습니다 Foo
. 그러나 우리는 a
~이다 x.Bar
그리고 유형 b
~이다 y.Bar
- 의미하는 것은 a
내부 클래스의 인스턴스입니다 Bar
외부 물체와 함께 x
, 비슷합니다 b
.
실제로 유형이 전화를 통해 다르다는 것을 알 수 있습니다. typeOf(a)
그리고 typeOf(b)
, 어디 typeOf
따라서 정의 된 유틸리티 방법입니다. (그것은 단지 아주 좋은 유형의 추론과 약간의 사용으로 인수의 유형을 제공합니다. Manifest
에스)
def typeOf[T](x: T)(implicit m: scala.reflect.Manifest[T]) = m.toString
내부 객체는 동봉 된 물체에 대한 참조를 가지고 있습니다. 할 수 없습니다 어쨌든 외부 물체를 지정하지 않고 내부 물체를 인스턴스화하십시오. 따라서 전화 할 수 있습니다 new x.Bar("one")
그러나 당신은 전화 할 수 없습니다 new Foo#Bar("?")
- 두 번째 케이스에서와 같이 구성하려는 새 개체의 내부 객체가 무엇인지 지정하지 않았습니다.
자, 코드 스 니펫으로 돌아가 봅시다. 패턴 일치 할 때는 실제로 생성자를 호출합니다. C1(e1)
. 처럼 C1
별명입니다 Container[TKey]#C1
외부 객체를 지정하지 않고 내부 클래스의 생성자를 호출하려고 시도했는데, 이는 위에서 설명한 이유로 인해 실패합니다. 코드를 작성하는 방식은 다음과 같습니다.
trait Container[TKey] {
abstract trait CB
case class C1(val e : AnyRef) extends CB
case class C2(val e : AnyRef) extends CB
}
class DoStuff[TKey] (val c: Container[TKey], val element: Container[TKey]#CB) {
element match {
case c.C1(e1) => Some(e1)
case c.C2(e2) => Some(e2)
case _ => None
}
}
이제 이것은 컴파일하고 당신이 원하는 것을하기를 바랍니다. 그러나 이것을 잘 돌봐주세요! 유형 삭제로 인해 Scala는 element
실제로 유형입니다 c.CB
또는 유형 d.CB
어디에 CB
의 경우 c
그리고 d
동일합니다.
이 예를 고려하십시오 :
def matcher(arg: Foo#Bar) = {
arg match {
case x.Bar(n) => println("x");
case y.Bar(n) => println("y");
}
}
어디 x
그리고 y
이전과 마찬가지로. 다음을 실행하십시오 :
matcher(a)
matcher(b)
둘 다 인쇄합니다 x
!
따라서 코드를 다시 작성하여 컨테이너에 요소를 명시 적으로 갖습니다.
trait Container[TKey] {
abstract trait CB
case class C1(val e : AnyRef) extends CB
case class C2(val e : AnyRef) extends CB
val element: CB
}
class DoStuff[TKey](val c: Container[TKey]) {
c.element match {
case c.C1(e1) => Some(e1)
case c.C2(e2) => Some(e2)
case _ => None
}
}
도움이되기를 바랍니다 :)
- flaviu cipcigan