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

การใช้ร่วมกับ Option และ Future

การเชื่อมต่อแบบโมนาดิก

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

นอกเหนือจากคอลเลกชัน

for-comprehension ไม่ได้จำกัดอยู่แค่ลิสต์ ประเภทใดก็ตามที่มี map และ flatMap ก็สามารถใช้ได้ รวมถึง Option, Either, Try และ Future แนวทางนี้เรียกว่า การเชื่อมโยงแบบโมนาดิก

object Main {
  def main(args: Array[String]): Unit = {
    val sum = for {
      a <- Some(10)
      b <- Some(20)
    } yield a + b
    println(sum)
  }
}

Option หยุดการทำงานทันทีเมื่อพบ None

เมื่อใช้ Option การทำความเข้าใจจะสร้างผลลัพธ์ก็ต่อเมื่อตัวสร้าง ทุกตัว เป็น Some หากมีตัวใดเป็น None ผลลัพธ์ทั้งหมดจะเป็น None และขั้นตอนถัดไปจะถูกข้าม

object Main {
  def main(args: Array[String]): Unit = {
    val ok = for {
      a <- Some(2)
      b <- Some(3)
    } yield a * b

    val missing = for {
      a <- Some(2)
      b <- None: Option[Int]
    } yield a * b

    println(ok)
    println(missing)
  }
}

การเชื่อมโยงการค้นหาค่าที่อาจไม่มี

รูปแบบที่ใช้บ่อยคือการค้นหาคีย์ใน Map ซึ่งการค้นหาแต่ละครั้งจะคืนค่าเป็น Option for-comprehension จะให้ค่าก็ต่อเมื่อการค้นหาทั้งหมดสำเร็จ

object Main {
  def main(args: Array[String]): Unit = {
    val prices = Map("apple" -> 3, "bread" -> 5)
    val total = for {
      a <- prices.get("apple")
      b <- prices.get("bread")
    } yield a + b
    println(total)

    val missing = for {
      a <- prices.get("apple")
      c <- prices.get("milk")
    } yield a + c
    println(missing)
  }
}

เหตุใดจึงดีกว่า if-else ซ้อนกัน

หากไม่ใช้ for-comprehension คุณจะต้องซ้อนการจับคู่รูปแบบหรือการตรวจสอบค่า null รูปแบบโมนาดิกจะคลี่พีระมิดนั้นออกเป็นลำดับเชิงเส้นที่อ่านง่าย

object Main {
  def parse(s: String): Option[Int] = s.toIntOption
  def main(args: Array[String]): Unit = {
    val result = for {
      x <- parse("40")
      y <- parse("2")
    } yield x + y
    println(result)
  }
}

การ์ดใช้กับ Option ได้เช่นกัน

การ์ดภายในการทำความเข้าใจแบบ Option จะเปลี่ยนค่าเป็น None เมื่อเงื่อนไขไม่ผ่าน ทำหน้าที่เป็นการตรวจสอบแบบแทรกในโค้ด

object Main {
  def main(args: Array[String]): Unit = {
    def validate(age: Int): Option[Int] =
      for {
        a <- Some(age)
        if a >= 18
      } yield a
    println(validate(25))
    println(validate(15))
  }
}

แนะนำ Future

Future แทนค่าที่จะพร้อมใช้งานในภายหลัง เช่นเดียวกับ Option ที่มี map และ flatMap ดังนั้น for-comprehension จึงสามารถเรียงลำดับขั้นตอนแบบไม่พร้อมกันได้

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
import scala.concurrent.duration._

object Main {
  def main(args: Array[String]): Unit = {
    val f = for {
      a <- Future(10)
      b <- Future(20)
    } yield a + b
    println(Await.result(f, 2.seconds))
  }
}

Future ทำงานตามลำดับในกรณีนี้

เมื่อเครื่องกำเนิดหนึ่งขึ้นอยู่กับอีกเครื่องกำเนิดหนึ่งภายใน for-comprehension ฟิวเจอร์จะทำงานตามลำดับ เพราะการเรียก flatMap แต่ละครั้งจะรอผลลัพธ์ก่อนหน้า

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
import scala.concurrent.duration._

object Main {
  def main(args: Array[String]): Unit = {
    val f = for {
      a <- Future(5)
      b <- Future(a * 2)
    } yield a + b
    println(Await.result(f, 2.seconds))
  }
}

การเรียกใช้ Future แบบขนาน

หากต้องการให้ฟิวเจอร์ทำงานแบบขนาน ให้เริ่มฟิวเจอร์เหล่านั้น ก่อน for-comprehension แล้วจึงนำมารวมกัน งานที่เป็นอิสระต่อกันจะทำงานทับซ้อนกันแทนการรอคอย

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
import scala.concurrent.duration._

object Main {
  def main(args: Array[String]): Unit = {
    val fa = Future(100)
    val fb = Future(200)
    val combined = for {
      a <- fa
      b <- fb
    } yield a + b
    println(Await.result(combined, 2.seconds))
  }
}

Either สำหรับข้อผิดพลาดที่มีรายละเอียดมากขึ้น

Either[E, A] จะเก็บค่าข้อผิดพลาดไว้เมื่อการทำงานล้มเหลว ใน for-comprehension เมื่อพบ Left ตัวแรก การทำงานจะหยุดทันทีและคืนค่า Left นั้น

object Main {
  def parse(s: String): Either[String, Int] =
    s.toIntOption.toRight(s"not a number: $s")
  def main(args: Array[String]): Unit = {
    val good = for { a <- parse("3"); b <- parse("4") } yield a + b
    val bad  = for { a <- parse("3"); b <- parse("x") } yield a + b
    println(good)
    println(bad)
  }
}

รูปแบบเดียวกันกับหลายประเภท

สังเกตว่าโครงสร้างของการทำความเข้าใจนั้น เหมือนกันทุกประการ ไม่ว่าจะใช้ Option, Either, Try หรือ Future สิ่งที่แตกต่างมีเพียงความหมายของความล้มเหลว ความสม่ำเสมอนี้คือพลังของการเชื่อมโยงแบบโมนาดิก

import scala.util.Try

object Main {
  def main(args: Array[String]): Unit = {
    val result = for {
      a <- Try("21".toInt)
      b <- Try("2".toInt)
    } yield a * b
    println(result)
  }
}

ไม่อนุญาตให้ผสมประเภท

ตัวสร้างทั้งหมดในการทำความเข้าใจเดียวกันต้องเป็นโมนาดชนิดเดียวกัน คุณไม่สามารถผสมตัวสร้าง Option กับตัวสร้าง Future ได้โดยตรง ต้องแปลงประเภทใดประเภทหนึ่งก่อน เช่น ใช้ Future.fromTry หรือห่อหุ้ม Option

object Main {
  def main(args: Array[String]): Unit = {
    // Convert the Option to keep types consistent
    val maybe: Option[Int] = Some(7)
    val result = for {
      a <- maybe
      b <- maybe.map(_ + 1)
    } yield a + b
    println(result)
  }
}

ตรวจสอบอย่างรวดเร็ว

ในการทำความเข้าใจแบบ Option จะเกิดอะไรขึ้นหากตัวสร้างตัวหนึ่งให้ค่าเป็น None

สรุปทบทวน

คุณได้เรียนรู้การเชื่อมโยงแบบโมนาดิกด้วย for-comprehension:

  • ใช้ได้กับทุกประเภทที่มี map และ flatMap
  • Option จะหยุดการทำงานทันทีเมื่อพบ None
  • Either และ Try จะหยุดการทำงานเมื่อเกิดความล้มเหลว พร้อมเก็บข้อมูลข้อผิดพลาดไว้
  • Future จะเรียงลำดับขั้นตอนแบบไม่พร้อมกัน ควรเริ่มขั้นตอนเหล่านั้นตั้งแต่เนิ่น ๆ หากต้องการทำงานแบบขนาน
  • ตัวสร้างทั้งหมดต้องใช้ประเภทโมนาดเดียวกัน

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

บทเรียน “การใช้ร่วมกับ Option และ Future” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “การใช้ร่วมกับ Option และ Future”

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

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

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

บทเรียน “การใช้ร่วมกับ Option และ Future” ใช้เวลานานแค่ไหน

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

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

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

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

  1. การคลี่รูป for
  2. การกรองด้วย if
  3. ตัวสร้างหลายตัว
  4. การใช้ร่วมกับ Option และ Future
← กลับไปที่ Scala for Backend Engineering & Functional Programming