In Scala è possibile recuperare la `Val` a cui si fa riferimento da un tipo singleton?
-
27-10-2019 - |
Domanda
Sto cercando di ottenere una forma minima di tipi dipendenti in Scala. Se ho
class A[T <: Int]
val x: Int = 7
io posso
val a = new A[x.type]
Ora è possibile recuperare x
Dal suo singleton x.type
?
Oppure, se ciò non è possibile, è possibile associare in qualche modo un identificatore stabile a un tipo e poi estrarlo?
Soluzione
No, non puoi recuperare x
da x.type
A causa della cancellazione del tipo JVM. Ad esempio, come sarebbe implementato?
def f[A]: A = ???
f[x.type]
A livello di bytecode JVM, non c'è modo f
può trovare valore x: A
dato A = x.type
Perché non ha nulla con cui lavorare: tutti i parametri del tipo sono persi in fase di esecuzione e comunque, il x
Il valore non è disponibile su f
Stack dei parametri.
Per lo stesso motivo, per ottenere un ID stabile di un tipo, dovresti reinserire come un Manifest
valore. Ma quando ci ho provato, ottengo uno strano risultato,
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 !?
Non sono sicuro del motivo per cui questi due manifesti di tipo sono uguali --- hanno anche diversi toString
rappresentazioni. Potrebbe essere un bug Scala? Aggiornare: Secondo il Scaladoc, Gli operatori di relazioni di tipo <: <e =: = dovrebbero essere considerati solo approssimazioni, in quanto vi sono numerosi aspetti della conformità del tipo che non sono ancora adeguatamente rappresentati nei manifesti.
Per riassumere, la reificazione delle informazioni del tipo nei valori di runtime non si verifica automaticamente su JVM. Scala's Manifest
dovrebbe colmare il divario, ma immagino che non funzioni con tipi dipendenti.
Altri suggerimenti
Per rispondere alla tua seconda domanda, "associando un identificatore stabile a un tipo", un modo per farlo è usare le classi di tipo. Diciamo che voglio associare una descrizione della stringa ai tipi, posso farlo come segue:
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"
}
Ora, per recuperare tali tag, inserisci la magia implicita:
def printTag[T : Tag] {
val tag = implicitly[Tag[T]]
println("Type is described as : " + tag.desc)
}
Per esempio:
printTag[String] // prints "Type is described as : character string"
printTag[Double] // compile-time error: no implicit value found of type Tag[Double]
Puoi persino generare tag se necessario, usando funzioni implicite. Per esempio:
implicit def liftTagToList[T : Tag] = new Tag[List[T]] {
val underlying = implicitly[Tag[T]].desc
val desc = "list of " + underlying + "s"
}
Ora posso fare quanto segue:
// prints "Type is described as : list of character strings"
printTag[List[String]]
e persino:
// prints "Type is described as : list of list of character stringss"
printTag[List[List[String]]]
Per favore perdona la pluralizzazione.