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 บทเรียน

ชนิดแบบทึบคืออะไร

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

  • ความปลอดภัยของชนิดเช่นเดียวกับคลาสห่อค่า
  • ไม่มีต้นทุนการจองหน่วยความจำ
object Distances:
  opaque type Meters = Double

object Main:
  def main(args: Array[String]): Unit =
    println("Opaque types compile to their underlying type")

การประกาศชนิดแบบทึบ

ประกาศชนิดแบบทึบภายในออบเจกต์หรือคลาส นอกขอบเขตนั้น Meters และ Double จะถือเป็นคนละชนิดกัน

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

ขอบเขตของความทึบ

ภายในขอบเขตที่กำหนด ชนิดแบบทึบกับชนิดพื้นฐานสามารถใช้แทนกันได้ ภายนอก จะมองเห็นเฉพาะชนิดแบบทึบ จึงไม่สามารถส่ง Double ดิบในตำแหน่งที่ต้องการ 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))

การเพิ่มเมธอดส่วนขยาย

เพิ่มพฤติกรรมให้ชนิดแบบทึบด้วย เมธอดส่วนขยายที่กำหนดในขอบเขตเดียวกัน ผู้เรียกใช้จะได้การดำเนินการที่สะดวก โดยไม่ต้องเปิดเผยชนิดพื้นฐาน

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)

การป้องกันการสับสนระหว่างชนิด

ข้อดีสำคัญคือ ชนิดแบบทึบสองชนิดที่ใช้ชนิดพื้นฐานเดียวกันจะ ใช้แทนกันไม่ได้ Meters จึงไม่อาจถูกสับสนกับ Kilometers แม้ว่าทั้งคู่จะเป็น Double ก็ตาม

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

ชนิดแบบทึบพร้อมขอบเขต

คุณสามารถกำหนด ขอบเขตบนให้ชนิดแบบทึบด้วย <: วิธีนี้จะเปิดเผย API สาธารณะบางส่วน แต่ยังซ่อนรูปแบบการแทนค่าที่แน่นอนไว้

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)

การสร้างค่าอัจฉริยะพร้อมการตรวจสอบ

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

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

ต้นทุนขณะทำงานเป็นศูนย์

แตกต่างจากตัวห่อหุ้มแบบคลาสค่าหรือคลาสกรณี ชนิดทึบแสงจะสร้างไม่มีออบเจ็กต์ขณะทำงาน List ของ Meters คือรายการของ double โดยตรงใน JVM จึงไม่มีการห่อค่า

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)

ชนิดทึบแสงเทียบกับนามแฝงชนิด

นามแฝง type X = Y แบบธรรมดามีความโปร่งใส กล่าวคือ X และ Y ใช้แทนกันได้ทุกที่ ชนิดที่ทึบแสงจะซ่อนความเท่าเทียมกันนี้นอกขอบเขต จึงให้ความปลอดภัยด้านชนิดอย่างแท้จริง

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)

ชนิดทึบแสงเทียบกับตัวห่อหุ้มแบบคลาสกรณี

ตัวห่อหุ้มแบบคลาสกรณี เช่น case class Meters(value: Double) ก็เพิ่มความปลอดภัยด้านชนิดเช่นกัน แต่จะจัดสรรออบเจ็กต์ ชนิดทึบแสงให้ความปลอดภัยแบบเดียวกันพร้อมประสิทธิภาพของชนิดพื้นฐาน

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)

ควรใช้ชนิดทึบแสงเมื่อใด

ใช้ชนิดทึบแสงเมื่อคุณต้องการชนิดที่สื่อความหมายของโดเมนอย่างเข้มงวดในเส้นทางที่ทำงานบ่อยหรือคอลเลกชันขนาดใหญ่

  • แยกปริมาณต่างชนิดกัน เช่น Meters กับ Seconds
  • บังคับใช้เงื่อนไขที่ผ่านการตรวจสอบแล้ว
  • หลีกเลี่ยงต้นทุนการจัดสรรของตัวห่อหุ้ม
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))

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

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

สรุปทบทวน

คุณได้เรียนรู้ชนิดทึบแสงของ Scala 3

  • opaque type X = Y ซ่อนความเท่าเทียมกันนอกขอบเขต
  • จัดเตรียมโรงงานและเมธอด extension สำหรับ API
  • ชนิดทึบแสงที่แตกต่างกันบนชนิดพื้นฐานเดียวกันไม่สามารถใช้แทนกันได้
  • ขอบเขตบนที่เป็นตัวเลือกพร้อม <: จะเปิดเผย API เพียงบางส่วน
  • ไม่มีต้นทุนขณะทำงาน ต่างจากตัวห่อหุ้มแบบคลาสกรณี
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)

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

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

ใช่ — ข้อความเต็มของ “ชนิดข้อมูลทึบแสง” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ 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. การย่อหน้าที่มีความหมาย
  2. อีนัมใน Scala 3
  3. ชนิดข้อมูลทึบแสง
  4. ชนิดข้อมูลยูเนียนและอินเตอร์เซกชัน
← กลับไปที่ Scala for Backend Engineering & Functional Programming