2016-03-29 13 views
1

Ist es möglich, eine Ente-Typisierung Stil Umwandlung zu haben, wo ein Konverter wird ein beliebiges Objekt übernehmen und versuchen, es zu dem Zieltyp zu konvertieren?Duck-Typing implizite Konvertierung in Scala

case class RequiredFields(name: String, surname: String) 
case class Person(name: String, surname: String, age: Option[Int]) 
implicit def arbitraryToPerson(object: ????): Person = Person(object.name, object.surname, None) 

beliebiges Objekt nicht zu RequriedField Klasse in irgendeiner Weise im Zusammenhang werden muss, nur müssen die Felder vorhanden sind.

Antwort

3

Ich denke, Sie können strukturelle Typisierung und implizite Konvertierungen kombinieren. Wie so:

type RequiredFields = { 
    def name: String 
    def surname: String 
} 

case class NotAPerson(name: String, surname: String) 
case class Person(name: String, surname: String, age: Option[Int]) 

implicit def arbitraryToPerson(o: RequiredFields): Person = Person(o.name, o.surname, None) 

val p:Person = NotAPerson("oh", "my") 

Sind Sie sicher, dass das eine gute Idee ist, obwohl? Ich denke, das viel bessere Muster hier wäre, eine Typklasse mit den erforderlichen Feldern zu definieren. Hast du das bedacht?

0

Ich denke, dass Sie für ein Merkmal freuen:

trait Nameable { 
    def name: String 
    def surname: String 
} 
case class Person(name: String, surname: String, age: Option[Int]) extends Nameable 
implicit def arbitraryToPerson(variable: Nameable): Person = Person(variable.name, variable.surname, None) 

Sie eines Merkmals wie eine Schnittstelle denken. Charakteristisch für Scala-Merkmale ist, dass sie auch Implementierungen ihrer Methoden akzeptieren.

Klassen, die diese Eigenschaft erweitern, müssen die Methoden name und surname implementieren. In diesem Fall wäre der einzige gültige benennbare Parameter eine Person. Mehr Klassen zu haben, die das Merkmal erweitern, würde eine Art von Polymorphismus erlauben, was dies implizit tatsächlich nützlich macht.

EDIT Von Ihrem Kommentar und negativ, nur um darauf hinzuweisen, dass Sie Ihre Merkmale aufrufen können, wie Sie möchten. In Ihrem Fall könnte etwas wie Nameable funktionieren. Es bedeutet nicht, dass es eine Hierarchie gibt, sondern dass Ihr Objekt bestimmte Bedingungen erfüllt, wie die Implementierung dieser Methoden. Klassen können mehr als ein Merkmal in Scala mit dem Schlüsselwort with erweitern.

case class Dog(name: String, surname: String) extends Animal with Nameable 

In diesem Fall würde Ihr Hund ein Tier sein, aber man kann durch die Verlängerung der Eigenschaft, die Umsetzung der Umbenennbar Methoden erzwingen.

+0

Nicht wirklich, ich mag keine Klassenhierarchie haben. Ich habe ein beliebiges Objekt, das eine Superklasse der Person sein könnte oder könnte. z.B. Die Konvertierung würde auf ALL-Objekten funktionieren, die Felder unabhängig von ihrer Vererbung haben. –

+0

@ ArtursVacans Dann müssen Sie den Typ Mensch für welchen Typ auch immer ändern, den Sie als Quelle der Daten verwenden möchten, um eine Person zu erstellen. Von diesem Moment an können Sie diesen Typ an einen Parameter vom Typ Person senden. – Khanser

+0

Ich gehe davon aus, dass das funktionieren würde, aber ich möchte meine Zieleinheit nicht mit zusätzlichen Eigenschaften verpesten:/ –

0

Als hasumedic beantwortet Sie wahrscheinlich ein Merkmal verwenden möchten.

Wenn Sie aus irgendeinem Grund kein Merkmal verwenden möchten (Sie haben keine Kontrolle über die Paketobjekte, die an Sie gesendet werden usw.), können Sie die Felder auch mit reflection abrufen. (Ich weiß nicht wirklich, ob dies eine gute Idee ist, aber meine beste Vermutung ist, dass es nicht ist)

case class RequiredFields(name: String, surname: String) 
val rF = new RequriedFields("Hey", "yo") 
val method = rF.getClass.getDeclaredMethod("name") 

Dann Sie Ihren Wert erhalten, indem die Getter für dieses Feld aufrufen, die scala für Sie macht

scala> val x = method.invoke(rF).asInstanceOf[String] 
x: String = Hey 
0

Es scheint, Sie Duck-Typing angetrieben Umwandlung in der folgenden Art und Weise zu tun:

implicit def convertToPerson(obj: {def name(value: String): String; def surname(): String}): Person = { 
    Person(obj.name, obj.surname, None) 
} 
+1

Sie können, aber wie Lutz bemerkt, sollten Sie nicht. Zumindest würde ich hoffen, dass niemand darauf zurückgreifen würde, außer unter ziemlich ungewöhnlichen Umständen. –

Verwandte Themen