0Pricing
Scala for Backend Engineering & Functional Programming · Lezione

Definire istanze

Istanze implicite

Definire istanze è una lezione Scala for Backend Engineering & Functional Programming gratuita su CoddyKit. Questa è la lezione 2 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.

Definire le istanze

Un'instance indica al compilatore come si comporta una classe di tipi per un tipo specifico. In Scala, le istanze sono generalmente contrassegnate come implicit (Scala 2) oppure dichiarate con given (Scala 3), così vengono individuate automaticamente.

Un'istanza implicit val

Per una classe di tipi semplice è sufficiente un implicit val. Il compilatore lo individua quando una funzione richiede un Show[Int].

trait Show[A] { def show(a: A): String }

object Main {
  implicit val intShow: Show[Int] = (a: Int) => s"Int=$a"

  def display[A](a: A)(implicit s: Show[A]): String = s.show(a)

  def main(args: Array[String]): Unit = {
    println(display(123))
  }
}

implicitly: richiamare un'istanza

implicitly[Show[Int]] chiede al compilatore di recuperare l'istanza disponibile nell'ambito corrente. È utile per verificare che un'istanza esista o per accedervi direttamente.

trait Show[A] { def show(a: A): String }

object Main {
  implicit val intShow: Show[Int] = (a: Int) => s"<$a>"

  def main(args: Array[String]): Unit = {
    val s = implicitly[Show[Int]]
    println(s.show(8))
  }
}

Istanze per tipi personalizzati

Definisca un'istanza per la propria case class. La classe dei dati rimane pulita; la formattazione risiede nell'istanza.

trait Show[A] { def show(a: A): String }

case class Point(x: Int, y: Int)

object Main {
  implicit val pointShow: Show[Point] = (p: Point) => s"(${p.x}, ${p.y})"

  def display[A](a: A)(implicit s: Show[A]): String = s.show(a)

  def main(args: Array[String]): Unit = {
    println(display(Point(3, 4)))
  }
}

implicit def per le istanze generiche

Quando un'istanza dipende da un'altra istanza, usi implicit def. Qui un Show[List[A]] viene costruito a partire da un Show[A].

trait Show[A] { def show(a: A): String }

object Main {
  implicit val intShow: Show[Int] = (a: Int) => a.toString

  implicit def listShow[A](implicit s: Show[A]): Show[List[A]] =
    (xs: List[A]) => xs.map(s.show).mkString("[", ", ", "]")

  def display[A](a: A)(implicit s: Show[A]): String = s.show(a)

  def main(args: Array[String]): Unit = {
    println(display(List(1, 2, 3)))
  }
}

Istanze nell'oggetto companion

Collocare le istanze nel companion object della classe di tipi fa sì che vengano individuate automaticamente senza alcun import. È il posto consigliato per le istanze predefinite.

trait Show[A] { def show(a: A): String }

object Show {
  implicit val intShow: Show[Int] = (a: Int) => s"i:$a"
  implicit val strShow: Show[String] = (a: String) => s"s:$a"
}

object Main {
  def display[A](a: A)(implicit s: Show[A]): String = s.show(a)

  def main(args: Array[String]): Unit = {
    println(display(5))
    println(display("hi"))
  }
}

Ambito e priorità degli impliciti

Il compilatore cerca un'istanza in diversi punti: prima nell'ambito locale o importato, poi nei companion object dei tipi coinvolti. Se due istanze sono ugualmente specifiche, si verifica un errore di implicit ambiguo.

Forma abbreviata del context bound

La sintassi def f[A: Show](a: A) è un context bound: significa che nell'ambito deve essere presente un Show[A] implicito. All'interno, lo recuperi con implicitly.

trait Show[A] { def show(a: A): String }

object Main {
  implicit val intShow: Show[Int] = (a: Int) => s"n=$a"

  def display[A: Show](a: A): String = implicitly[Show[A]].show(a)

  def main(args: Array[String]): Unit = {
    println(display(77))
  }
}

Un helper per richiamare le istanze

Le librerie aggiungono un metodo apply al companion come comodo summoner: Show[Int] restituisce l'istanza. È più pulito di implicitly.

trait Show[A] { def show(a: A): String }

object Show {
  def apply[A](implicit s: Show[A]): Show[A] = s
  implicit val intShow: Show[Int] = (a: Int) => s"=$a"
}

object Main {
  def main(args: Array[String]): Unit = {
    println(Show[Int].show(10))
  }
}

Evitare le istanze orfane

Un'istanza orfana è definita al di fuori sia della classe di tipi sia del tipo. È legale, ma può causare comportamenti incoerenti tra gli import. Preferisca le istanze nei companion object per mantenerle coerenti.

Riunire tutti gli elementi

Un programma completo: istanze nei companion object, un'istanza derivata per le liste e un summoner.

trait Show[A] { def show(a: A): String }

object Show {
  def apply[A](implicit s: Show[A]): Show[A] = s
  implicit val intShow: Show[Int] = _.toString
  implicit def listShow[A](implicit s: Show[A]): Show[List[A]] =
    (xs: List[A]) => xs.map(s.show).mkString(", ")
}

object Main {
  def main(args: Array[String]): Unit = {
    println(Show[List[Int]].show(List(4, 5, 6)))
  }
}

Verifica rapida

Verifichi la sua conoscenza della definizione delle istanze.

Riepilogo

Ha imparato a definire le istanze:

  • implicit val per le istanze semplici, implicit def per quelle derivate.
  • Richiami un'istanza con implicitly o con un apply del companion.
  • Usi i context bound [A: Show] come forma abbreviata.
  • Inserisca le istanze nei companion object per evitare istanze orfane.

Domande Frequenti

La lezione «Definire istanze» è gratuita?

Sì — il testo completo di «Definire istanze» è 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 «Definire istanze»?

Istanze implicite 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 2 di 4.

Quanto tempo richiede la lezione «Definire istanze»?

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

  1. Il pattern dei type class
  2. Definire istanze
  3. Type class comuni
  4. Derivazione delle type class
← Torna a Scala for Backend Engineering & Functional Programming