0Pricing
Scala for Backend Engineering & Functional Programming · Lección

Tipos opacos

Abstracciones sin coste

Tipos opacos es una lección gratuita de Scala for Backend Engineering & Functional Programming en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Scala for Backend Engineering & Functional Programming, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Scala for Backend Engineering & Functional Programming incluye 4 lecciones en total.

¿Qué son los tipos opacos?

Los tipos opacos son una característica de Scala 3 que permite crear abstracciones sin coste. Proporcionan un tipo distinto en tiempo de compilación, pero se compilan como el tipo subyacente sin envoltorio en tiempo de ejecución.

  • La seguridad de tipos de una clase envoltorio.
  • Coste de asignación nulo.
object Distances:
  opaque type Meters = Double

object Main:
  def main(args: Array[String]): Unit =
    println("Opaque types compile to their underlying type")

Declaración de un tipo opaco

Declare un tipo opaco dentro de un objeto o una clase. Fuera de ese ámbito, Meters y Double se consideran tipos distintos.

object Distances:
  opaque type Meters = Double
  def meters(d: Double): Meters = d
  def toDouble(m: Meters): Double = m

object Main:
  def main(args: Array[String]): Unit =
    val d = Distances.meters(5.0)
    println(Distances.toDouble(d))

El límite de la opacidad

Dentro del ámbito donde se define, el tipo opaco y su tipo subyacente son intercambiables. Fuera de él, solo se ve el tipo opaco, por lo que no puede pasar accidentalmente un Double sin envolver donde se requiere Meters.

object Distances:
  opaque type Meters = Double
  def apply(d: Double): Meters = d
  def show(m: Meters): String = s"$m m"

object Main:
  def main(args: Array[String]): Unit =
    val m = Distances(10.0)
    println(Distances.show(m))

Adición de métodos de extensión

Dote de comportamiento a los tipos opacos mediante métodos de extensión definidos en el mismo ámbito. Los usuarios obtienen operaciones cómodas sin exponer el tipo subyacente.

object Distances:
  opaque type Meters = Double
  def apply(d: Double): Meters = d
  extension (m: Meters)
    def +(other: Meters): Meters = m + other
    def value: Double = m

object Main:
  def main(args: Array[String]): Unit =
    val total = Distances(3.0) + Distances(4.0)
    println(total.value)

Prevención de confusiones

La principal ventaja es que dos tipos opacos sobre el mismo tipo subyacente son incompatibles. Meters no se puede confundir con Kilometers, aunque ambos sean Doubles.

object Units:
  opaque type Meters = Double
  opaque type Kilometers = Double
  def m(d: Double): Meters = d
  def km(d: Double): Kilometers = d
  def toMeters(k: Kilometers): Meters = k * 1000

object Main:
  def main(args: Array[String]): Unit =
    val far = Units.km(2.0)
    println(Units.toMeters(far))

Tipos opacos con límites

Puede proporcionar a un tipo opaco un límite superior con <:. Esto expone parte de la API pública y mantiene oculta la representación exacta.

object Ids:
  opaque type UserId <: Int = Int
  def apply(i: Int): UserId = i

object Main:
  def main(args: Array[String]): Unit =
    val id = Ids(99)
    println(id + 1)

Construcción segura con validación

Combine tipos opacos con una fábrica que valide los valores para garantizar que siempre sean válidos. El constructor permanece privado; solo la fábrica validada es pública.

object Ages:
  opaque type Age = Int
  def of(i: Int): Option[Age] =
    if i >= 0 && i < 150 then Some(i) else None
  extension (a: Age) def value: Int = a

object Main:
  def main(args: Array[String]): Unit =
    println(Ages.of(30).map(_.value))
    println(Ages.of(-1))

Coste nulo en tiempo de ejecución

A diferencia de un envoltorio de clase de valor o case class, un tipo opaco no crea ningún objeto en tiempo de ejecución. Una List de Meters es literalmente una lista de doubles en la JVM, por lo que no hay boxing.

object Temps:
  opaque type Celsius = Double
  def c(d: Double): Celsius = d
  extension (t: Celsius) def value: Double = t

object Main:
  def main(args: Array[String]): Unit =
    val readings = List(Temps.c(20.0), Temps.c(21.5))
    println(readings.map(_.value).sum)

Tipo opaco frente a alias de tipo

Un alias normal type X = Y es transparente: X e Y son completamente intercambiables en cualquier lugar. Un tipo opaco oculta esa igualdad fuera de su ámbito y proporciona seguridad de tipos real.

object Demo:
  type Name = String          // transparent alias
  opaque type Email = String  // opaque
  def email(s: String): Email = s
  extension (e: Email) def raw: String = e

object Main:
  def main(args: Array[String]): Unit =
    val e = Demo.email("a@b.com")
    println(e.raw)

Tipo opaco frente a envoltorio case class

Un envoltorio case class como case class Meters(value: Double) también añade seguridad de tipos, pero reserva un objeto. Los tipos opacos ofrecen la misma seguridad con el rendimiento del tipo sin envolver.

object Money:
  opaque type Cents = Long
  def cents(n: Long): Cents = n
  extension (c: Cents)
    def +(o: Cents): Cents = c + o
    def value: Long = c

object Main:
  def main(args: Array[String]): Unit =
    val total = Money.cents(150) + Money.cents(50)
    println(total.value)

Cuándo usar tipos opacos

Use tipos opacos cuando quiera una tipificación de dominio sólida en rutas críticas o colecciones grandes.

  • Distinguir magnitudes (Meters frente a Seconds).
  • Garantizar invariantes validadas.
  • Evitar el coste de asignación de los envoltorios.
object Geo:
  opaque type Latitude = Double
  def lat(d: Double): Option[Latitude] =
    if d >= -90 && d <= 90 then Some(d) else None
  extension (l: Latitude) def value: Double = l

object Main:
  def main(args: Array[String]): Unit =
    println(Geo.lat(41.0).map(_.value))

Comprobación rápida

Compruebe su comprensión de los tipos opacos.

Resumen

Ha aprendido los tipos opacos de Scala 3.

  • opaque type X = Y oculta la igualdad fuera de su ámbito.
  • Proporcione fábricas y métodos extension para la API.
  • Los distintos tipos opacos sobre la misma base son incompatibles.
  • Los límites superiores opcionales con <: exponen parte de la API.
  • Coste nulo en tiempo de ejecución, a diferencia de los envoltorios case class.
object Ids:
  opaque type OrderId = String
  def apply(s: String): OrderId = s
  extension (o: OrderId) def raw: String = o

object Main:
  def main(args: Array[String]): Unit =
    val id = Ids("ORD-1")
    println(id.raw)

Preguntas frecuentes

¿La lección «Tipos opacos» es gratis?

Sí — el texto completo de «Tipos opacos» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Scala for Backend Engineering & Functional Programming, actualiza a CoddyKit PRO. El curso de Scala for Backend Engineering & Functional Programming incluye 4 lecciones en total.

¿Qué aprenderé en «Tipos opacos»?

Abstracciones sin coste Practicas Scala for Backend Engineering & Functional Programming con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Scala for Backend Engineering & Functional Programming?

No se requiere experiencia previa. Scala for Backend Engineering & Functional Programming en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.

¿Cuánto tiempo toma la lección «Tipos opacos»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Scala for Backend Engineering & Functional Programming?

Sí. Cada lección de Scala for Backend Engineering & Functional Programming incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Indentación significativa
  2. Enums en Scala 3
  3. Tipos opacos
  4. Tipos unión e intersección
← Volver a Scala for Backend Engineering & Functional Programming