문제

별명 유형과 일치하는 케이스 클래스를 어떻게 사용합니까? 이것은 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

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