Voglio eliminare un cast di esecuzione su un generico (asInstanceOf[A]
) senza conversioni implicite.Copia di restituzione della classe del caso dalla funzione generica senza cast di esecuzione
Ciò accade quando ho un modello di dati abbastanza pulito costituito da case classes con un tratto comune e voglio implementare un algoritmo generico su di esso. Ad esempio, l'algoritmo risultante dovrebbe prendere una classe di tipo A
che è una sottoclasse di trait T
e deve restituire una copia della classe di calcestruzzo A
con un campo aggiornato.
Questo è facile da ottenere quando posso semplicemente aggiungere un metodo astratto copy
al tratto base e implementarlo in tutte le sottoclassi. Tuttavia questo potenzialmente inquina il modello con metodi richiesti solo da determinati algoritmi e talvolta non è possibile perché il modello potrebbe essere fuori dal mio controllo.
Ecco un esempio semplificato per dimostrare il problema e una soluzione che utilizza i cast di esecuzione.
Per favore non rimanere impigliato nei dettagli.
Supponiamo che ci sia un tratto e alcune classi di casi che non posso cambiare:
trait Share {
def absolute: Int
}
case class CommonShare(
issuedOn: String,
absolute: Int,
percentOfCompany: Float)
extends Share
case class PreferredShare(
issuedOn: String,
absolute: Int,
percentOfCompany: Float)
extends Share
Ed ecco un metodo semplice per ricalcolare la corrente percentOfCompany
quando il numero totale di azioni sono cambiati e aggiornare il campo in la classe caso
def recalculateShare[A <: Share](share: A, currentTotalShares: Int): A = {
def copyOfShareWith(newPercentage: Float) = {
share match {
case common: CommonShare => common.copy(percentOfCompany = newPercentage)
case preferred: PreferredShare => preferred.copy(percentOfCompany = newPercentage)
}
}
copyOfShareWith(share.absolute/currentTotalShares.toFloat).asInstanceOf[A]
}
Alcuni esempi di invocazioni sulla REPL:
scala> recalculateShare(CommonShare("2014-01-01", 100, 0.5f), 400)
res0: CommonShare = CommonShare(2014-01-01,100,0.25)
scala> recalculateShare(PreferredShare("2014-01-01", 50, 0.5f), 400)
res1: PreferredShare = PreferredShare(2014-01-01,50,0.125)
Quindi funziona e per quanto ho capito la chiamata .asInstanceOf[A]
non fallirà mai ma è richiesta per compilare il codice. C'è un modo per evitare il cast runtime in modo sicuro al tipo senza conversioni implicite?
Io non la penso così. Avresti bisogno di una prova implicita del typetag. In caso contrario, si ottiene un problema di cancellazione del tipo. –