2017-11-04 4 views
0

Ich möchte eine Sammlung von Objekten, jedes Objekt ein Begleiter einer anderen Klasse, die alle eine gemeinsame Methode in einer Oberklasse definiert, die beim Durchlaufen der Sammlung mit einem foreach() aufgerufen werden kann. Ich möchte, dass die Konstruktoren dieser Geschwisterklassen dieselben benannten Parameter und Standardparameterwerte als einander haben. Schließlich möchte ich wiederholten Code minimieren.Scala-Sammlung, deren Elemente Geschwisterinstanzen mithilfe benannter Parameter und Standardwerte erstellen können?

Bis jetzt versuche ich dies mit Fallklassen zu tun, da - wenn es funktioniert - es den gesamten duplizierten Code der Companion-Objekte für jeden Typ eliminieren würde. Das Problem ist, dass, wenn ich alle diese Begleitobjekte in eine Set setze, wenn ich sie wieder herausnehme, die Standardparameter und Parameternamen verliere. Hier

ist einige Beispiel-Code von dem, was ich beschreibe:

trait MyType { 
    val param: String 
    def label = param // all instances of all subclasses have this method 
} 

case class caseOne(override val param: String = "default") extends MyType 
case class caseTwo(override val param: String = "default") extends MyType 

object Main extends App { 
    // I can construct instances using the companion objects' `apply()` method: 
    val works1 = caseOne(param = "I have been explicitly set").label 
    // I can construct instances that have the default parameter value 
    val works2 = caseOne().label 

    // But what I want to do is something like this: 
    val set = Set(caseOne, caseTwo) 
    for { 
    companion <- set 
    } { 
    val fail1 = companion()      // Fails to compile--not enough arguments 
    val fail2 = companion(param = "not default") // Fails also as param has lost its name 
    val succeeds = companion("nameless param") // this works but not what I want 
    println(fail1.label + fail2.label)   // this line is my goal 
    } 
} 

Insbesondere, wenn die Set nur ein Element hat, dann kompiliert, was auf die abgeleitete Art des Multi-Element-Set fehlt der Parameter Namen- obwohl sie gleich sind und die Standardwerte. Wenn ich den Set den richtigen Typparameter gebe, könnte das auch funktionieren. Aber was wäre das für ein Typ? Nicht MyType da dies der Typ der Companion-Klassen ist eher, dass die Objekte in der Set.

Ich könnte die Begleitobjekte explizit definieren, aber das ist der wiederholte Code, den ich vermeiden möchte.

Wie kann ich meine Sammlung durchlaufen, Instanzen von MyType Unterklassen bei jeder Iteration konstruieren, mit Konstruktoren, die meine gewünschten Parameternamen und Standardwerte haben? All dies minimiert den wiederholten Code.

Update: Ursprünglich ist der Beispielcode zeigte caseOne und caseTwo wie für param verschiedene Standardwerte. Das war falsch; sie sind jetzt gleich.

Antwort

0

Sie werden nicht in der Lage sein, genau das zu bekommen, was Sie wollen, da Sie nicht wirklich viel Kontrolle über die automatisch generierten Begleitobjekte haben. Damit dies funktioniert, müssen sie alle ein gemeinsames Merkmal ausprägen. Deshalb kann es nicht kompiliert werden, wenn der Satz mehr als ein Begleitobjekt hat. Obwohl sie alle eine Methode mit der gleichen Signatur haben, erweitern sie kein gemeinsames Merkmal für den Compiler.

Sie eine verschachtelte Fall-Klasse verwenden können, und wenn etwas sehr ähnliches erhalten:

trait MyType { 
    val param: String 
    def label = param // all instances of all subclasses have this method 
} 

abstract class MyTypeHelper(default: String) { 

    case class Case(param: String) extends MyType 

    def apply(param: String) : Case = Case(param) 
    def apply(): Case = apply(default) 
} 

object One extends MyTypeHelper("default one") 
object Two extends MyTypeHelper("default two") 

object Example { 

    val works1 = One(param = "I have been explicitly set").label 
    val works2 = One().label 

    val set = Set(One, Two) 
    for { 
    companion <- set 
    } { 
    val a = companion()      
    val b = companion(param = "not default") 
    val c = companion("nameless param") 
    println(a.label + b.label)   
    } 
} 

Statt eine caseOne Art zu haben, haben Sie One.Case, aber es setzt noch MyType so sollten Sie kein Problem haben überall sonst in dem Code, der dieses Merkmal verwendet.

+0

Das sieht so aus, danke! Hinweis: Ich habe im ursprünglichen Beispielcode einen Fehler gemacht: Die beiden Fallklassen sollten (und haben jetzt) ​​denselben Standardwert haben. Weil ich den 'MyTypeHelper' mit einer einzigen' apply() 'Methode verwenden konnte, die den Standardwert definiert und den' default' Parameter aus dem 'MyTypeHelper' Konstruktor entfernt hat. Ich habe auch "Case" von einer Case-Klasse in eine reguläre Klasse geändert und dabei ein Zeichen gespeichert. Du hast mich losgemacht; vielen Dank nochmal! –

Verwandte Themen