Opaque Types
Abstraktionen ohne Laufzeitkosten
Opaque Types ist eine kostenlose Scala for Backend Engineering & Functional Programming-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Scala for Backend Engineering & Functional Programming-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Scala for Backend Engineering & Functional Programming-Kurs umfasst insgesamt 4 Lektionen.
Was sind opaque types?
Opaque types sind eine Scala-3-Funktion zum Erstellen von Abstraktionen ohne Laufzeitkosten. Sie stellen zur Compile-Zeit einen eigenen Typ dar, werden aber ohne Laufzeit-Wrapper auf den zugrunde liegenden Typ kompiliert.
- Typsicherheit einer Wrapper-Klasse.
- Kein zusätzlicher Speicherallokationsaufwand.
object Distances:
opaque type Meters = Double
object Main:
def main(args: Array[String]): Unit =
println("Opaque types compile to their underlying type")Einen opaque type deklarieren
Deklarieren Sie einen opaque type innerhalb eines Objekts oder einer Klasse. Außerhalb dieses Gültigkeitsbereichs werden Meters und Double als unterschiedliche Typen behandelt.
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))Die Grenze der Opazität
Innerhalb des definierenden Gültigkeitsbereichs sind der opaque type und sein zugrunde liegender Typ austauschbar. Außerhalb ist nur der opaque type sichtbar. Daher können Sie nicht versehentlich ein rohes Double übergeben, wenn Meters erforderlich ist.
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))Extension Methods hinzufügen
Geben Sie opaque types mit im selben Gültigkeitsbereich definierten Extension Methods ein bestimmtes Verhalten. Aufrufende erhalten komfortable Operationen, ohne dass der zugrunde liegende Typ offengelegt wird.
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)Verwechslungen verhindern
Der entscheidende Vorteil: Zwei opaque types über demselben zugrunde liegenden Typ sind inkompatibel. Meters kann nicht mit Kilometers verwechselt werden, obwohl beide Doubles sind.
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))Opaque types mit Bounds
Sie können einem opaque type mit <: einen oberen Bound geben. Dadurch wird ein Teil der öffentlichen API sichtbar, während die genaue Repräsentation verborgen bleibt.
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)Intelligente Konstruktion mit Validierung
Kombinieren Sie opake Typen mit einer validierenden Factory, um sicherzustellen, dass Werte immer gültig sind. Der Konstruktor bleibt privat; nur die validierte Factory ist öffentlich.
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))Keine Laufzeitkosten
Im Gegensatz zu einem Wrapper auf Basis einer Value Class oder Case Class erzeugt ein opaker Typ zur Laufzeit kein Objekt. Eine Liste von Metern ist auf der JVM tatsächlich eine Liste von Doubles, daher gibt es kein 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)Opaker Typ vs. Typalias
Ein einfacher Alias type X = Y ist transparent: X und Y sind überall vollständig austauschbar. Ein opaker Typ verbirgt diese Gleichheit außerhalb seines Gültigkeitsbereichs und bietet dadurch echte Typsicherheit.
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)Opaker Typ vs. Case-Class-Wrapper
Ein Case-Class-Wrapper wie case class Meters(value: Double) bietet ebenfalls Typsicherheit, erzeugt aber ein Objekt. Opake Typen bieten dieselbe Sicherheit mit der Performance des zugrunde liegenden Typs.
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)Wann Sie opake Typen verwenden sollten
Verwenden Sie opake Typen, wenn Sie eine starke Domänentypisierung in zeitkritischen Codepfaden oder großen Collections benötigen.
- Unterscheiden Sie Größen (Meter vs. Sekunden).
- Erzwingen Sie validierte Invarianten.
- Vermeiden Sie den Allokationsaufwand von Wrappern.
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))Kurzer Check
Testen Sie Ihr Verständnis opaker Typen.
Zusammenfassung
Sie haben die opaken Typen von Scala 3 kennengelernt.
opaque type X = Yverbirgt die Gleichheit außerhalb seines Gültigkeitsbereichs.- Stellen Sie Factorys und
extension-Methoden für die API bereit. - Verschiedene opake Typen über derselben Basis sind inkompatibel.
- Optionale obere Schranken mit
<:legen einen Teil der API offen. - Keine Laufzeitkosten im Gegensatz zu Case-Class-Wrappern.
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)Häufig gestellte Fragen
Ist die Lektion „Opaque Types“ kostenlos?
Ja — der vollständige Text von „Opaque Types“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Scala for Backend Engineering & Functional Programming-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Scala for Backend Engineering & Functional Programming-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Opaque Types“?
Abstraktionen ohne Laufzeitkosten Du übst Scala for Backend Engineering & Functional Programming mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um Scala for Backend Engineering & Functional Programming zu starten?
Keine Vorkenntnisse erforderlich. Scala for Backend Engineering & Functional Programming auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.
Wie lange dauert die Lektion „Opaque Types“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser Scala for Backend Engineering & Functional Programming-Lektion Code schreiben und ausführen?
Ja. Jede Scala for Backend Engineering & Functional Programming-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.