Scala for Backend Engineering & Functional Programming · Pelajaran

Newtype

Pembungkus yang aman terhadap tipe

Pelajaran 3 dari 413 langkah

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 differ

Masalah 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 class untuk kesederhanaan, dan opaque type tanpa 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)
Gratis untuk memulai

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.

Semua pelajaran dalam kursus ini

  1. Pemodelan dengan ADT
  2. Konstruktor Cerdas
  3. Newtype
  4. Menggabungkan Domain
← Kembali ke Scala for Backend Engineering & Functional Programming