Ist es in Scala möglich, das von einem Singleton -Typ verwiesene "Val" abzurufen?
-
27-10-2019 - |
Frage
Ich versuche, eine minimale Form von abhängigen Typen in Scala zu erhalten. Wenn ich habe
class A[T <: Int]
val x: Int = 7
ich kann
val a = new A[x.type]
Jetzt ist es möglich, sich zu erholen x
von seinem Singleton x.type
?
Oder, wenn das nicht möglich ist, ist es möglich, eine stabile Kennung irgendwie mit einem Typ zu verknüpfen und dann zu extrahieren?
Lösung
Nein, Sie können sich nicht erholen x
aus x.type
Wegen des JVM -Typs. Wie würde dies zum Beispiel implementiert?
def f[A]: A = ???
f[x.type]
Auf der JVM -Bytecode -Ebene gibt es keine Möglichkeit f
kann Wert finden x: A
gegeben A = x.type
Weil es nichts zu arbeiten gibt: Alle Typparameter gehen zur Laufzeit verloren und trotzdem die x
Wert ist nicht verfügbar auf f
Parameterstapel.
Aus dem gleichen Grund müssten Sie es als stabile Art eines Typs erhalten Manifest
Wert. Aber als ich es versuchte, bekomme ich ein seltsames Ergebnis,
def f[A : Manifest] = implicitly[Manifest[A]]
val x = "hi"
val y = "ho"
println(f[x.type]) // hi.type
println(f[y.type]) // ho.type
f[x.type] == f[y.type] // true !?
Ich bin mir nicht sicher, warum diese beiden Typen gleich sind-sie haben sogar unterschiedlich toString
Darstellungen. Könnte dies ein Scala -Fehler sein? Aktualisieren: Laut dem Scaladoc, Die Typ-Relationsoperatoren <: <und =: = sollten nur als Approximationen betrachtet werden, da es zahlreiche Aspekte der Typ-Konformität gibt, die in Manifests noch nicht angemessen dargestellt werden.
Zusammenfassend lässt sich sagen, dass die Wiedergabe von Typinformationen in Laufzeitwerte nicht automatisch auf dem JVM stattfindet. Scala Manifest
soll die Lücke füllen, aber ich denke, es funktioniert nicht mit abhängigen Typen.
Andere Tipps
Um Ihre zweite Frage zu beantworten, "eine stabile Kennung mit einem Typ zu verknüpfen", besteht eine Möglichkeit, dies zu tun, um Typklassen zu verwenden. Nehmen wir an, ich möchte eine String -Beschreibung mit Typen in Verbindung bringen. Ich kann dies wie folgt tun:
trait Tag[A] {
val desc : String
}
implicit object StringTag extends Tag[String] {
val desc = "character string"
}
implicit object IntTag extends Tag[Int] {
val desc = "32-bit integer"
}
Um solche Tags wiederherzustellen, geben Sie die implizite Magie ein:
def printTag[T : Tag] {
val tag = implicitly[Tag[T]]
println("Type is described as : " + tag.desc)
}
Z.B:
printTag[String] // prints "Type is described as : character string"
printTag[Double] // compile-time error: no implicit value found of type Tag[Double]
Sie können nach Bedarf sogar Tags generieren, indem Sie implizite Funktionen verwenden. Zum Beispiel:
implicit def liftTagToList[T : Tag] = new Tag[List[T]] {
val underlying = implicitly[Tag[T]].desc
val desc = "list of " + underlying + "s"
}
Ich kann jetzt Folgendes machen:
// prints "Type is described as : list of character strings"
printTag[List[String]]
und sogar:
// prints "Type is described as : list of list of character stringss"
printTag[List[List[String]]]
Bitte vergib der Pluralisierung.