0Pricing
Scala for Backend Engineering & Functional Programming · บทเรียน

ชนิดข้อมูลใหม่

ตัวห่อหุ้มที่ปลอดภัยด้านชนิดข้อมูล

ชนิดข้อมูลใหม่ เป็นบทเรียน Scala for Backend Engineering & Functional Programming ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Scala for Backend Engineering & Functional Programming และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Scala for Backend Engineering & Functional Programming มีบทเรียนทั้งหมด 4 บทเรียน

ตัวห่อหุ้มที่ปลอดภัยด้านชนิด

นิวไทป์คือชนิดที่แตกต่างซึ่งห่อหุ้มค่าพื้นฐานไว้หนึ่งค่า ช่วยป้องกันการสับสนระหว่างค่าที่มีรูปแทนพื้นฐานเดียวกัน เช่น UserId และ ProductId ที่เป็น 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

ปัญหาการยึดติดกับชนิดพื้นฐาน

การยึดติดกับชนิดพื้นฐานคือการใช้ String และ Int มากเกินไปกับแนวคิดของโดเมน ทำให้เกิดเรื่องไร้เหตุผล เช่น ส่งอีเมลไปยังตำแหน่งที่ควรเป็นชื่อ นิวไทป์แก้ปัญหานี้ด้วยการให้แต่ละแนวคิดมีชนิดของตนเอง

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")))

นิวไทป์แบบคลาสกรณี

นิวไทป์ที่ง่ายที่สุดคือ case class ที่มีฟิลด์เดียว มันมอบความเท่าเทียมกัน เมธอด toString ที่อ่านง่าย และการจับคู่รูปแบบให้โดยอัตโนมัติ แต่มีต้นทุนการจัดสรรออบเจกต์หนึ่งรายการต่อค่า

case class OrderId(value: String)

object Main:
  def main(args: Array[String]): Unit =
    val id = OrderId("ORD-42")
    println(id)
    println(id.value)

นิวไทป์แบบชนิดทึบแสง

หากต้องการไม่จัดสรรออบเจกต์ ให้สร้างนิวไทป์ด้วยชนิดทึบแสง ขณะทำงานจะมีพฤติกรรมเหมือนชนิดพื้นฐาน แต่ในเวลาคอมไพล์จะเป็นชนิดที่แตกต่างกัน

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)

เพิ่มพฤติกรรมด้วยส่วนขยาย

เพิ่มการดำเนินการให้นิวไทป์ผ่านเมธอด extension โดยเปิดเผยเฉพาะสิ่งที่เหมาะสมกับแนวคิดของโดเมน

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)

นิวไทป์ในลายเซ็นฟังก์ชัน

นิวไทป์ทำให้ลายเซ็นอธิบายตัวเองได้และตรวจจับข้อผิดพลาดจากลำดับอาร์กิวเมนต์ตั้งแต่เวลาคอมไพล์ คุณจะสลับพารามิเตอร์ของนิวไทป์ต่างชนิดกันโดยไม่ตั้งใจไม่ได้

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)))

นิวไทป์และคอลเลกชัน

Map ที่ใช้คีย์เป็นนิวไทป์ชัดเจนและปลอดภัยกว่าการใช้ Int ดิบ ระบบชนิดจะป้องกันไม่ให้ใช้คีย์ผิดประเภท

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)))

นิวไทป์ที่ผ่านการตรวจสอบ

ผสานนิวไทป์กับตัวสร้างอัจฉริยะเพื่อให้ตัวห่อหุ้มบังคับใช้เงื่อนไขคงที่ด้วย ในกรณีนี้ NonEmptyString จะไม่มีวันว่าง

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(""))

การเลือกตัวแทนข้อมูล

เลือกตามความต้องการของคุณ

  • case class: ง่ายที่สุด จับคู่รูปแบบได้ และจัดสรรออบเจกต์
  • opaque type: ไม่มีต้นทุน ไม่มีการห่อค่า เหมาะสำหรับเส้นทางที่ทำงานบ่อยและคอลเลกชันขนาดใหญ่
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)

ป้องกันการแปลงโดยไม่ตั้งใจ

นิวไทป์สองชนิดที่สร้างบนชนิดพื้นฐานเดียวกันจะไม่แปลงให้โดยอัตโนมัติ หากต้องการแปลงระหว่างกัน คุณต้องเขียนฟังก์ชันอย่างชัดเจนเพื่อบันทึกเจตนา

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)))

ควรใช้นิวไทป์เมื่อใด

เลือกใช้นิวไทป์เมื่อใดก็ตามที่ชนิดพื้นฐานมีความหมายในโดเมน

  • ตัวระบุ หน่วย และสตริงที่มีรูปแบบกำหนด
  • ใช้ case class เพื่อความเรียบง่าย และ opaque type เพื่อประสิทธิภาพ
  • เพิ่มตัวสร้างอัจฉริยะเมื่อมีเงื่อนไขคงที่
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))

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ทดสอบความเข้าใจของคุณเกี่ยวกับนิวไทป์

สรุปทบทวน

คุณได้เรียนรู้นิวไทป์

  • นิวไทป์ห่อหุ้มค่าพื้นฐานหนึ่งค่าไว้ในชนิดที่แตกต่าง
  • ช่วยแก้ปัญหาการยึดติดกับชนิดพื้นฐานและป้องกันการสลับอาร์กิวเมนต์
  • ใช้ case class เพื่อความเรียบง่าย และ opaque type เพื่อไม่มีต้นทุน
  • เพิ่มตัวสร้างอัจฉริยะสำหรับตัวห่อหุ้มที่ผ่านการตรวจสอบ
  • การแปลงระหว่างนิวไทป์ต้องระบุอย่างชัดเจนเสมอ
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)

คำถามที่พบบ่อย

บทเรียน “ชนิดข้อมูลใหม่” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “ชนิดข้อมูลใหม่” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Scala for Backend Engineering & Functional Programming ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Scala for Backend Engineering & Functional Programming มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “ชนิดข้อมูลใหม่”

ตัวห่อหุ้มที่ปลอดภัยด้านชนิดข้อมูล คุณปฏิบัติ Scala for Backend Engineering & Functional Programming ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Scala for Backend Engineering & Functional Programming หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Scala for Backend Engineering & Functional Programming บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “ชนิดข้อมูลใหม่” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Scala for Backend Engineering & Functional Programming นี้ได้ไหม

ได้ บทเรียน Scala for Backend Engineering & Functional Programming ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การสร้างแบบจำลองด้วย ADT
  2. ตัวสร้างอัจฉริยะ
  3. ชนิดข้อมูลใหม่
  4. การประกอบโดเมน
← กลับไปที่ Scala for Backend Engineering & Functional Programming