2016-11-08 3 views
0

Ich habe eine Klasse mit mehreren verschiedenen Konstruktoren, die sich in den Typen von Parametern unterscheiden, wenn alle diese Parameter von derselben Basisklasse ausgehen.Scala - Konstruktor nach Laufzeittyp auswählen Konstruktorargumente

Sehen Sie hier für ein vereinfachtes Beispiel:

abstract case class GeneralDataType() 
case class SpecificDataTypeOne() extends GeneralDataType 
case class SpecificDataTypeTwo() extends GeneralDataType 

case class MyNumber(myDataType: Int) extends { 
    def this(data: SpecificDataTypeOne) = this(1) 
    def this(data: SpecificDataTypeTwo) = this(2) 
} 

def getDataType(typeId: Int): GeneralDataType = typeId match { 
    case 1 => new SpecificDataTypeOne 
    case 2 => new SpecificDataTypeTwo 
} 

val x = getDataType(1) 

// error: Cannot resolve constructor 
val mn = new MyNumber(x) 

Wie in Runtime den richtigen Konstruktor zu verwenden, entsprechend den Parametertypen zu wählen?

+0

in Eclipse Ich erhalte diese error: case-Klasse SpecificDataTypeOne hat den case-Vorgänger GeneralDataType, aber die fallweise Vererbung ist unzulässig. Um diese Einschränkung zu umgehen, verwenden Sie Extraktoren, um die Übereinstimmung von Mustern auf Nicht-Blattknoten zu ermitteln. –

Antwort

1

Wie andere vorgeschlagen, versuchen Begleiter Objekt als Fabrik zu verwenden (ich noch Fehler, dass ich einen Kommentar hinzugefügt haben, aber könnte sein, es ist scala Version abhängig?)

object MyNumber { 
    def apply(x:GeneralDataType) : MyNumber = x match { 
     case SpecificDataTypeOne() => new MyNumber(1) 
     case SpecificDataTypeTwo() => new MyNumber(2) 
    } 

    def getDataType(typeId: Int): GeneralDataType = typeId match { 
     case 1 => new SpecificDataTypeOne 
     case 2 => new SpecificDataTypeTwo 
    } 
    val x = getDataType(1) 
    val mn = MyNumber(x) 
} 
case class MyNumber(myDataType: Int) 


abstract case class GeneralDataType() 
    case class SpecificDataTypeOne() extends GeneralDataType 
    case class SpecificDataTypeTwo() extends GeneralDataType 
1

Nicht genau sicher, dass Sie den Fall verwenden. Während Companion-Objekt kann in dem Fall verwendet werden.

object MyNumber { 
    def apply(typeId: Int): MyNumber = typeId match { 
    case 1 => new MyNumber(new SpecificDataTypeOne) 
    case 2 => new MyNumber(new SpecificDataTypeTwo) 
    } 
} 

val mn = MyNumber(1) 
+0

Hallo, ich denke du hast die Frage missverstanden. Ich bekomme ein Objekt von beiden Typen (SpecificDataTypeOne oder Two) von außerhalb und möchte dann den entsprechenden Konstruktor basierend auf seinem Typ aufrufen. –

0

Wenn Sie es gerade tun müssen, um für eine GeneralDataType (oder vielleicht ein paar) und ein paar Konstrukteurs jeweils, wird Pattern-Matching tun, was Sie brauchen:

x match { 
    case y1: SpecificDataTypeOne => new MyNumber(y1) 
    case y2: SpecificDataTypeTwo => new MyNumber(y2) 
} 

Sie können eine mehr machen allgemeine Lösung mit Reflexion, aber es sollte nur verwendet werden, wenn das oben genannte nicht gut genug ist.

+0

Wenn ich versuche, MyNumbers Konstruktor zu überlasten, um Ihren Code zu enthalten, funktioniert es nicht ... –

+0

Sie meinen etwas wie 'def this (Daten: GeneralDataType) = Daten übereinstimmen ...'? Nein, wird es nicht. Verwenden Sie stattdessen eine 'apply'-Methode im Companion-Objekt, wie in Rockie Yangs Antwort (nehmen Sie' GeneralDataType' als Argument). –

Verwandte Themen