Frage

Wie verwende ich Fall passende Klasse mit alias-Typen?Dies funktioniert, wenn ich pull-CB etc out of Container.

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
}

Vielen Dank!

War es hilfreich?

Lösung

Rechts...Innere Klassen in Scala sind ein bisschen fummelig.Lassen Sie uns versuchen, ein einfaches Beispiel, bevor zeige ich Euch die überarbeitete version von dem code, den Sie zur Verfügung gestellt haben.

case class Foo(x: Int) {
  case class Bar(y: String) 
}

Betrachten Sie nun das folgende code-snippet:

val x = new Foo(1)
val y = new Foo(2)

val a = new x.Bar("one")
val b = new y.Bar("two") 

Die meisten generischen Typ a und b ist Foo#Bar, was bedeutet, dass die innere Klasse Bar mit jedem äußeren Objekt vom Typ Foo.Aber wir könnten genauer sein, zu sagen, dass die Art der a ist x.Bar und die Art der b ist y.Bar - was bedeutet, dass a ist eine Instanz der inneren Klasse Bar mit dem äußeren Objekt x, ähnlich für b.

Sie können tatsächlich sehen, dass die Typen unterschiedlich sind, durch den Aufruf typeOf(a) und typeOf(b), wo typeOf ist eine utility-Methode als solche bezeichnet.(es gibt nur die Art von argument, die von ganz netter Typ-Inferenz und ein bisschen Einsatz Manifests)

def typeOf[T](x: T)(implicit m: scala.reflect.Manifest[T]) = m.toString

Als ein inneres Objekt enthält einen Verweis auf die einschließende Objekt, Sie nicht instanziieren eines inneren Objekts, ohne irgendwie Angabe seiner äußeren Objekt.Daher, Sie können rufen new x.Bar("one") aber Sie kann nicht rufen new Foo#Bar("?") - wie im zweiten Fall, dass Sie noch nicht angegeben, was ist das innere Objekt für das neue Objekt, das Sie versuchen zu konstruieren.

Also, lassen Sie uns zurück zu Ihrem code-snippet.Wenn Sie pattern-matching, die Sie eigentlich aufrufen einer Konstruktor - aufrufen, wenn C1(e1).Als C1 ist ein alias für Container[TKey]#C1 Sie versuchte zu rufen, einen Konstruktor der inneren Klasse, ohne Angabe seiner äußeren Objekt, die nicht aufgrund der oben aufgeführten Gründe.Die Art, wie ich schreiben würde, würde der code wie folgt:

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
  }
}

Jetzt dies kompiliert und hoffentlich tut es das, was Sie wollen.Aber nehmen Sie dies mit großer Sorgfalt!Durch type erasure, Scala nicht garantieren, dass die element ist eigentlich der Typ c.CB oder der Typ d.CB wo die CB im Falle der c und d geschehen die gleichen zu sein.

Betrachten Sie dieses Beispiel:

def matcher(arg: Foo#Bar) = {
  arg match {
    case x.Bar(n) => println("x");
    case y.Bar(n) => println("y");
  }
}

wo x und y sind wie vorher.Versuchen Sie den folgenden Befehl ausführen:

matcher(a)
matcher(b) 

Beide drucken x!

Daher würde ich den code neu schreiben, um explizit ein element im container:

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
  }
}

Hoffe es hilft :)

-- Flaviu Cipcigan

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top