Newtype
Pembungkus yang aman terhadap tipe
Newtype adalah pelajaran Scala for Backend Engineering & Functional Programming gratis di CoddyKit. Ini adalah pelajaran 3 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Scala for Backend Engineering & Functional Programming, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Scala for Backend Engineering & Functional Programming mencakup 4 pelajaran total.
Pembungkus yang Aman Tipe
Newtype adalah tipe berbeda yang membungkus satu nilai yang mendasarinya. Newtype mencegah tertukarnya nilai yang memiliki representasi primitif sama, seperti UserId dan ProductId yang sama-sama berupa Int.
case class UserId(value: Int)
case class ProductId(value: Int)
object Main:
def main(args: Array[String]): Unit =
val u = UserId(1)
val p = ProductId(1)
println(u.value == p.value) // values equal, types differMasalah Penggunaan Primitif Secara Berlebihan
Penggunaan primitif secara berlebihan adalah penggunaan String dan Int secara berlebihan untuk konsep domain. Hal ini memungkinkan kekeliruan seperti mengirim email saat yang diperlukan adalah nama. Newtype memperbaikinya dengan memberikan tipe tersendiri untuk setiap konsep.
case class Email(value: String)
case class City(value: String)
object Main:
def greet(c: City): String = s"Welcome to ${c.value}"
def main(args: Array[String]): Unit =
println(greet(City("Berlin")))Newtype dengan Case Class
Newtype paling sederhana adalah case class dengan satu bidang. Newtype ini langsung menyediakan kesetaraan, toString yang mudah dibaca, dan pencocokan pola. Kekurangannya adalah alokasi satu objek untuk setiap nilai.
case class OrderId(value: String)
object Main:
def main(args: Array[String]): Unit =
val id = OrderId("ORD-42")
println(id)
println(id.value)Newtype dengan Tipe Opaque
Untuk menghindari alokasi, implementasikan newtype dengan tipe opaque. Tipe ini berperilaku seperti tipe yang mendasarinya saat runtime, tetapi tetap berbeda saat kompilasi.
object Ids:
opaque type UserId = Int
def apply(i: Int): UserId = i
extension (u: UserId) def value: Int = u
object Main:
def main(args: Array[String]): Unit =
val u = Ids(7)
println(u.value)Menambahkan Perilaku dengan Ekstensi
Berikan operasi pada newtype melalui metode extension, dan tampilkan hanya operasi yang masuk akal untuk konsep domain tersebut.
object Money:
opaque type Cents = Long
def apply(n: Long): Cents = n
extension (c: Cents)
def +(o: Cents): Cents = c + o
def toDollars: Double = c / 100.0
object Main:
def main(args: Array[String]): Unit =
val total = Money(250) + Money(750)
println(total.toDollars)Newtype dalam Tanda Tangan Fungsi
Newtype membuat tanda tangan mendokumentasikan dirinya sendiri dan menemukan kesalahan urutan argumen saat kompilasi. Anda tidak dapat secara tidak sengaja menukar dua parameter dari newtype yang berbeda.
case class Width(value: Int)
case class Height(value: Int)
object Main:
def area(w: Width, h: Height): Int = w.value * h.value
def main(args: Array[String]): Unit =
println(area(Width(4), Height(5)))Newtype dan Koleksi
Map yang menggunakan newtype sebagai kunci lebih jelas dan aman daripada Map yang menggunakan Int mentah sebagai kunci. Tipe ini mencegah penggunaan jenis kunci yang salah.
case class UserId(value: Int)
object Main:
def main(args: Array[String]): Unit =
val names = Map(UserId(1) -> "Ada", UserId(2) -> "Bob")
println(names(UserId(2)))Newtype yang Telah Divalidasi
Gabungkan newtype dengan konstruktor cerdas agar pembungkusnya juga menegakkan invariant. Dalam hal ini, NonEmptyString tidak mungkin kosong.
case class NonEmptyString private (value: String)
object NonEmptyString:
def of(s: String): Option[NonEmptyString] =
if s.nonEmpty then Some(NonEmptyString(s)) else None
object Main:
def main(args: Array[String]): Unit =
println(NonEmptyString.of("hi"))
println(NonEmptyString.of(""))Memilih Representasi
Pilih berdasarkan kebutuhan Anda.
- case class: paling mudah, dapat digunakan untuk pencocokan pola, tetapi mengalokasikan objek.
- opaque type: tanpa biaya, tanpa boxing, ideal untuk jalur yang sering dijalankan dan koleksi besar.
object Temp:
opaque type Kelvin = Double
def apply(d: Double): Kelvin = d
extension (k: Kelvin) def value: Double = k
object Main:
def main(args: Array[String]): Unit =
val readings = List(Temp(300.0), Temp(310.5))
println(readings.map(_.value).sum)Mencegah Konversi yang Tidak Disengaja
Dua newtype di atas tipe dasar yang sama tidak dikonversi secara implisit. Untuk berpindah di antara keduanya, Anda harus menulis fungsi eksplisit yang mendokumentasikan maksudnya.
case class Meters(value: Double)
case class Feet(value: Double)
object Main:
def toFeet(m: Meters): Feet = Feet(m.value * 3.281)
def main(args: Array[String]): Unit =
println(toFeet(Meters(2.0)))Kapan Menggunakan Newtype
Gunakan newtype setiap kali sebuah primitif membawa makna domain.
- Identifier, satuan, string berformat.
- Gunakan case class untuk kesederhanaan, dan tipe opaque untuk kinerja.
- Tambahkan konstruktor cerdas jika terdapat invariant.
object Domain:
opaque type Sku = String
def of(s: String): Option[Sku] =
if s.startsWith("SKU-") then Some(s) else None
extension (k: Sku) def raw: String = k
object Main:
def main(args: Array[String]): Unit =
println(Domain.of("SKU-9").map(_.raw))Pemeriksaan Singkat
Uji pemahaman Anda tentang newtype.
Ringkasan
Anda telah mempelajari newtype.
- Newtype membungkus satu nilai dasar dalam tipe yang berbeda.
- Newtype mengatasi penggunaan primitif secara berlebihan dan mencegah kekeliruan argumen.
- Gunakan
case classuntuk kesederhanaan, danopaque typetanpa biaya. - Tambahkan konstruktor cerdas untuk pembungkus yang tervalidasi.
- Konversi antar-newtype selalu harus eksplisit.
object Ids:
opaque type AccountId = Long
def apply(n: Long): AccountId = n
extension (a: AccountId) def value: Long = a
object Main:
def main(args: Array[String]): Unit =
val acc = Ids(1001L)
println(acc.value)Belajar Scala dengan tutor AI — gratis
Tulis dan jalankan kode asli di browser kamu, dapatkan bantuan instan dari tutor AI 24/7, dan lanjutkan di mana kamu tinggalkan di web atau aplikasi.
- Kursus
- 39
- Pelajaran
- 143
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Newtype” gratis?
Ya — teks lengkap “Newtype” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Scala for Backend Engineering & Functional Programming, upgrade ke CoddyKit PRO. Kursus Scala for Backend Engineering & Functional Programming mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Newtype”?
Pembungkus yang aman terhadap tipe Kamu berlatih Scala for Backend Engineering & Functional Programming dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai Scala for Backend Engineering & Functional Programming?
Tidak diperlukan pengalaman sebelumnya. Scala for Backend Engineering & Functional Programming di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 3 dari 4.
Berapa lama pelajaran “Newtype” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran Scala for Backend Engineering & Functional Programming ini?
Ya. Setiap pelajaran Scala for Backend Engineering & Functional Programming menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.