2017-11-19 3 views
0

HINWEIS: Wenn jemand einen besseren Titel für das, was ich versuchen möchte, zu finden - bitte erwähnen oder bearbeiten.Grenzen für Konstruktoren?

ein Wrap Verfahren Gegeben:

trait MyWrapperBound { 
    val message: String 
} 

def wrap[T <: MyWrapperBound](message: String): T 

ich nach einem Weg suchen, um zu beschreiben, dass alle alle Implementierungen von MyWrapperBound einen Konstruktor haben sollten, die ein message: String so dauert kann ich bauen und schicken Sie es aus meiner wrap Methode .

Ich denke an ein paar Möglichkeiten, dies zu tun:

Methode 1 - mit Hilfe eines impliziten:

def wrap[T <: MyWrapperBound](message: String)(implicit factory: String => T): T 

dies, daß MyWrapperBound impl bedeuten würde. müsste auch das implizite erzeugen:

case class SimpleBound(message: String) extends MyWrapperBound 

object SimpleBound { 
    implicit def factory(message: String): SimpleBound = SimpleBound(message) 
} 

Das würde zu einer ordentlichen Menge Vorlagentafel führen - was ich gerne vermeiden würde.

Methode 2 - Makro:

def wrap[T <: MyWrapperBound](message: String): T = macro ... 

Das Makro die Art nehmen würde, behaupten es ist ein gültiger Konstruktor, die Art der Konstruktion, wenn sein dort und einen schönen Compiler-Fehler, wenn nicht für den Entwickler werfen gehen und reparieren (durch Hinzufügen eines gültigen Konstruktors)

Meine Frage ist - für Scala ziemlich neu, gibt es eine einfachere Option, die ich vermisse? oder eine andere Option, die mehr Sinn macht?

+0

Methode 1 und Methode 2 sind verschiedene Dinge. In Methode 1 sprechen Sie darüber, wie Sie es mit einer impliziten Methode implementieren würden, und in Methode 2 sprechen Sie darüber, wie Sie die Validierung mithilfe eines Makros durchführen würden. Wussten Sie, dass Sie in Methode 2 einen Konstruktor für den Typ mithilfe eines Makros generieren möchten? –

+0

Ja, sie sind unterschiedliche Wege, um dasselbe Ziel zu erreichen. Methode 2 würde nur den Konstruktor validieren und verwenden, wenn er bereits vorhanden ist. Wenn es nicht da ist, wäre es Aufgabe des Entwicklers, es hinzuzufügen, um den Kompilierungsfehler zu beheben. – Cheetah

+0

@YuvalItzchakov - Ich habe gerade den Fehler gesehen, den ich gemacht habe, was meiner Meinung nach zu Ihrem Kommentar geführt hat. Die Makroversion sollte keinen impliziten Parameter haben .... sorry für irgendeine Verwirrung. – Cheetah

Antwort

0

Wenn Sie typeclasses zugänglich sind, gibt es eine etwas einfachere Antwort mit implicits. Sie können das, was Sie versuchen, relativ einfach erreichen, indem Sie MyWrapperBound einen Typparameter hinzufügen und die Nachrichtentypen auflisten, die Sie mit der Typenklasse Show unterstützen möchten. wenn man alles zum Beispiel weiß, dass Sie unterstützten einzuwickeln Karte A => String versuchen, könnten Sie ein Show[A] implizit auf Ihre wrap Methode, wie so liefern:

trait Show[A] { 

    def show(a: A): String 
} 

trait MyWrapperBound[A] { 

    val message: String 

} 

object MyWrapperBound { 

    def wrap[A](a: => A)(implicit ev: Show[A]): MyWrapperBound[A] = 
    new MyWrapperBound[A] { 
     override val message: String = ev.show(a) 
    } 
} 

object ShowInstances { 

    case class MyDS(someInformation: List[String]) 

    implicit val simpleShow: Show[String] = new Show[String] { 
    override def show(a: String): String = a 
    } 

    implicit val slightlyMoreComplexShow: Show[MyDS] = new Show[MyDS] { 
    override def show(a: MyDS): String = a.someInformation.mkString("[", ",", "]") 
    } 
} 

Wie immer, wird der Code kompilieren und erzeugt die gewünschte Ausgabe. Das Hinzufügen weiterer Unterstützung ist so einfach wie das Hinzufügen weiterer Instanzen zu ShowInstances. Dies ermöglicht Ihnen, die Karte A => String von der Wrapper-Logik selbst zu entkoppeln, so dass wrap ein einfacher Konstruktor für MyWrapperBound wird.

Wenn Sie nicht die Idee haben, Ihre MyWrapperBound mit einem Typparameter zu parametrisieren, ist es nicht einmal notwendig, wenn Sie nicht vorhaben, Instanzen davon durch einen Nachrichtentyp indiziert zu haben.

Verwandte Themen