Il pattern dei type class
Polimorfismo ad hoc
Il pattern dei type class è una lezione Scala for Backend Engineering & Functional Programming gratuita su CoddyKit. Questa è la lezione 1 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Scala for Backend Engineering & Functional Programming, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Scala for Backend Engineering & Functional Programming include 4 lezioni in totale.
Che cos'è una classe di tipi?
Una classe di tipi è un modello per aggiungere comportamento ai tipi senza modificarli. È una forma di polimorfismo ad hoc: la stessa operazione funziona con molti tipi non correlati, scelti dal compilatore in base al tipo.
Il concetto proviene da Haskell ed è ampiamente usato nelle librerie Scala come Cats.
Il problema che risolve
L'ereditarietà impone il comportamento a un tipo al momento della definizione. Tuttavia, spesso non può modificare un tipo, perché appartiene a una libreria, oppure desidera comportamenti diversi in contesti diversi. Le classi di tipi consentono di associare il comportamento esternamente.
Passaggio 1: definire il trait
Una classe di tipi è un trait parametrizzato da un tipo. Qui Show[A] descrive come eseguire il rendering di un qualunque A come String.
trait Show[A] {
def show(value: A): String
}
@main def run(): Unit = {
println("Show trait defined")
}Passaggio 2: fornire le istanze
Per ogni tipo concreto che desidera supportare, crei un'instance del trait. Queste sono le istanze della classe di tipi.
trait Show[A] { def show(value: A): String }
object Main {
val intShow: Show[Int] = (v: Int) => s"Int($v)"
val strShow: Show[String] = (v: String) => s"Str($v)"
def main(args: Array[String]): Unit = {
println(intShow.show(7))
println(strShow.show("hi"))
}
}Passaggio 3: usare l'istanza
Una funzione riceve l'istanza come parametro. La stessa funzione render funziona con qualunque tipo che disponga di un'istanza Show.
trait Show[A] { def show(value: A): String }
object Main {
def render[A](value: A, s: Show[A]): String = s.show(value)
val intShow: Show[Int] = (v: Int) => s"<$v>"
def main(args: Array[String]): Unit = {
println(render(99, intShow))
}
}Rendere l'istanza implicita
Passare le istanze manualmente è tedioso. Contrassegnando l'istanza e il parametro come implicit (o usando using in Scala 3), il compilatore può fornirli automaticamente.
trait Show[A] { def show(value: A): String }
object Main {
implicit val intShow: Show[Int] = (v: Int) => s"<$v>"
def render[A](value: A)(implicit s: Show[A]): String = s.show(value)
def main(args: Array[String]): Unit = {
println(render(42))
}
}Polimorfismo ad hoc
Lo stesso nome di funzione seleziona implementazioni diverse in base al tipo dell'argomento. Questo è il polimorfismo ad hoc, distinto dal polimorfismo per sottotipi (ereditarietà) e dal polimorfismo parametrico (generics).
trait Show[A] { def show(value: A): String }
object Main {
implicit val intShow: Show[Int] = (v: Int) => s"int:$v"
implicit val boolShow: Show[Boolean] = (v: Boolean) => s"bool:$v"
def render[A](value: A)(implicit s: Show[A]): String = s.show(value)
def main(args: Array[String]): Unit = {
println(render(5))
println(render(true))
}
}Lavorare con tipi personalizzati
Il vero vantaggio consiste nell'aggiungere comportamento ai propri tipi in modo pulito, mantenendo la classe dei dati libera da considerazioni di formattazione.
trait Show[A] { def show(value: A): String }
case class User(name: String, age: Int)
object Main {
implicit val userShow: Show[User] = (u: User) => s"${u.name} (${u.age})"
def render[A](value: A)(implicit s: Show[A]): String = s.show(value)
def main(args: Array[String]): Unit = {
println(render(User("Ada", 36)))
}
}Classi di tipi e interfacce
Un'interfaccia lega il comportamento alla definizione del tipo; una classe di tipi li disaccoppia.
- Può aggiungere un'istanza di una classe di tipi a un tipo che non appartiene al proprio codice.
- Può avere più istanze per contesti diversi.
- Il comportamento viene selezionato dal compilatore nel punto della chiamata.
Tre componenti
Ogni classe di tipi ha tre componenti:
- Il trait (l'operazione astratta).
- Le istanze (le implementazioni per ciascun tipo).
- L'interfaccia (le funzioni che richiedono un'istanza).
Esaminerà ciascun componente nelle lezioni successive.
Un esempio completo e minimale
Riunire il modello in un'unica funzione generica che usa un'istanza implicita.
trait Show[A] { def show(value: A): String }
object Main {
implicit val intShow: Show[Int] = (v: Int) => s"#$v"
implicit val strShow: Show[String] = (v: String) => '"' + v + '"'
def printAll[A](xs: List[A])(implicit s: Show[A]): Unit =
xs.foreach(x => println(s.show(x)))
def main(args: Array[String]): Unit = {
printAll(List(1, 2, 3))
printAll(List("a", "b"))
}
}Verifica rapida
Verifichi la sua comprensione del modello delle classi di tipi.
Riepilogo
Ha imparato il modello delle classi di tipi:
- Un
traitparametrizzato descrive un'operazione. - Le istanze la implementano per ciascun tipo.
- I parametri
implicitconsentono al compilatore di fornire l'istanza. - Questo offre polimorfismo ad hoc e consente di estendere tipi che non appartengono al proprio codice.
Domande Frequenti
La lezione «Il pattern dei type class» è gratuita?
Sì — il testo completo di «Il pattern dei type class» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Scala for Backend Engineering & Functional Programming, passa a CoddyKit PRO. Il corso Scala for Backend Engineering & Functional Programming include 4 lezioni in totale.
Cosa imparerò in «Il pattern dei type class»?
Polimorfismo ad hoc Eserciti Scala for Backend Engineering & Functional Programming con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Scala for Backend Engineering & Functional Programming?
Non è richiesta alcuna esperienza precedente. Scala for Backend Engineering & Functional Programming su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 4.
Quanto tempo richiede la lezione «Il pattern dei type class»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Scala for Backend Engineering & Functional Programming?
Sì. Ogni lezione Scala for Backend Engineering & Functional Programming include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Il pattern dei type class
- Definire istanze
- Type class comuni
- Derivazione delle type class