Entschlüsselung eines der härtesten Prototypen der Scala-Methode (slick)

8

Betrachten Sie die Methode <> in der folgenden skalaren Klasse, von Ссылка , es erinnert mich an

matanster 22.12.2014, 10:26
quelle

1 Antwort

20

Ok, werfen wir einen Blick darauf:

%Vor%

Die Klasse ist ein AnyVal wrapper; Während ich die implicit Umwandlung von einem schnellen Blick nicht wirklich sehen kann, riecht es wie das "pimp my library" -Muster. Ich vermute also, dass <> als "Erweiterungsmethode" für einige (oder vielleicht alle) Typen hinzugefügt werden soll.

@inline ist eine Annotation, eine Möglichkeit, Metadaten auf etwas zu setzen. Dies ist ein Hinweis für den Compiler, dass dies inline sein sollte. <> ist der Methodenname - viele Dinge, die wie "Operatoren" aussehen, sind einfache Methoden in scala.

Die von Ihnen verlinkte Dokumentation hat die R: ClassTag bereits auf gewöhnliche R und eine implicit ClassTag[R] erweitert - das ist ein "context bound" und es ist einfach syntaktischer Zucker. ClassTag ist ein vom Compiler generiertes Ding, das für jeden (konkreten) Typ existiert und bei der Reflektion hilft, also ist dies ein Hinweis darauf, dass die Methode wahrscheinlich irgendwann an einem R reflektiert.

Nun, das Fleisch: Dies ist eine generische Methode, die durch zwei Typen parametrisiert wird: [R, U] . Seine Argumente sind zwei Funktionen, f: U => R und g: R => Option[U] . Das sieht ein wenig wie das funktionale Konzept Prism aus - eine Konvertierung von U nach R , die immer funktioniert, und eine Konvertierung von R nach U , die manchmal nicht funktioniert.

Der interessante Teil der Signatur (Art) ist der implicit shape am Ende. Shape wird als "typeclass" bezeichnet, daher ist dies wohl am besten als "constraint" gedacht: es begrenzt die möglichen Typen U und R , mit denen wir diese Funktion bezeichnen können, auf diejenigen, für die ein Das entsprechende Shape ist verfügbar.

Sehen Sie sich die Dokumentation für Shape , sehen wir, dass die vier Typen Level , Mixed , Unpacked und Packed sind. Die Einschränkung ist also: Es muss ein Shape sein, dessen "Level" ein Untertyp von FlatShapeLevel ist, wobei der Mixed Typ T ist und der Unpacked Typ R (der Packed Typ kann ein beliebiger Typ sein.)

Also ist dies eine Typ-Level-Funktion, die ausdrückt, dass R "die entpackte Version von" T ist. Um das Beispiel aus der Shape -Dokumentation wieder zu verwenden, wenn T ist (Column[Int], Column[(Int, String)], (Int, Option[Double])) , dann R wird (Int, (Int, String), (Int, Option[Double]) (und es funktioniert nur für FlatShapeLevel , aber ich werde eine Beurteilung machen, dass das ist wahrscheinlich nicht wichtig). U ist interessanterweise völlig unbeschränkt.

Damit können wir ein MappedProjection[unpacked-version-of-T, U] von jedem T erzeugen, indem wir Konvertierungsfunktionen in beide Richtungen bereitstellen. In einer einfachen Version ist also T eine Column[String] - eine Repräsentation einer Spalte String in einer Datenbank - und wir möchten sie als einen anwendungsspezifischen Typ darstellen, z. %Code%. Also EmailAddress , R=String , und wir bieten Konvertierungsfunktionen in beide Richtungen: U=EmailAddress und f: EmailAddress => String . Es macht Sinn, dass es so ist: Jedes g: String => Option[EmailAddress] kann als EmailAddress dargestellt werden (zumindest sollten sie besser sein, wenn wir sie in der Datenbank speichern wollen), aber nicht jedes String ist eine gültige String . Wenn unsere Datenbank irgendwie z. " Ссылка " in der E-Mail-Adressspalte würde% code%% EmailAddress zurückgeben, und Slick könnte das elegant handhaben.

>

g selbst ist leider undokumentiert. Aber ich vermute, es ist eine Art von fauler Darstellung einer Sache, die wir abfragen können; wo wir ein None hatten, haben wir jetzt ein Pseudo-Spalten-Ding, dessen (unterliegender) Typ MappedProjection ist. Dies erlaubt uns, Pseudo-Anfragen wie 'Wählen Sie von Benutzern, bei denen emailAddress.domain =' gmail.com '' zu schreiben, was direkt in der Datenbank nicht möglich wäre (die nicht wissen, welcher Teil einer Email-Adresse ist) die Domäne), ist aber einfach mit Hilfe von Code zu tun. Zumindest ist das meine beste Schätzung, was es tun könnte.

Möglicherweise könnte die Funktion klarer gemacht werden, indem ein Standardtyp Column[String] (z. B. der von Monocle) verwendet wird, statt ein Paar Funktionen explizit zu übergeben. Die Verwendung des Impliziten zur Bereitstellung einer Typ-Level-Funktion ist umständlich, aber notwendig. In einer vollständig abhängigen typisierten Sprache (z. B. Idris) könnten wir unsere Typ-Level-Funktion als eine Funktion schreiben (etwas wie EmailAddress ). Diese Funktion sieht konzeptionell so aus:

%Vor%

Dies erklärt hoffentlich einige Gedanken zum Lesen einer neuen, unbekannten Funktion. Ich kenne Slick überhaupt nicht, also habe ich keine Ahnung, wie genau ich bin, wofür dieses Prism verwendet wird - habe ich es richtig verstanden?

    
lmm 22.12.2014 12:19
quelle

Tags und Links