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 = Yoculta la igualdad fuera de su ámbito.- Proporcione fábricas y métodos
extensionpara 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.