การคลี่รูป for
map และ flatMap
การคลี่รูป for เป็นบทเรียน Scala for Backend Engineering & Functional Programming ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Scala for Backend Engineering & Functional Programming และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Scala for Backend Engineering & Functional Programming มีบทเรียนทั้งหมด 4 บทเรียน
for-comprehension คืออะไร
for-comprehension ใน Scala คือไวยากรณ์พิเศษสำหรับทำงานกับคอลเลกชันและชนิดข้อมูลที่เป็นภาชนะอื่น ๆ รูปแบบดูคล้ายลูปแบบคำสั่ง แต่จริง ๆ แล้วเป็น รูปแบบย่อทางไวยากรณ์ ที่คอมไพเลอร์จะแปลงกลับเป็นการเรียก map, flatMap, filter และ foreach
การเข้าใจการแปลงกลับนี้ช่วยให้คุณวิเคราะห์ for-comprehension ได้ทุกแบบ แม้จะใช้กับชนิดข้อมูลที่กำหนดเอง
object Main {
def main(args: Array[String]): Unit = {
val result = for (x <- List(1, 2, 3)) yield x * 10
println(result)
}
}ตัวสร้างเดียวจะกลายเป็น map
เมื่อ for-comprehension มีตัวสร้างเพียงหนึ่งตัวและใช้ yield คอมไพเลอร์จะแปลงเป็นการเรียก map เพียงครั้งเดียว
for (x <- xs) yield f(x)- จะกลายเป็น
xs.map(x => f(x))
object Main {
def main(args: Array[String]): Unit = {
val a = for (x <- List(1, 2, 3)) yield x + 1
val b = List(1, 2, 3).map(x => x + 1)
println(a == b)
}
}คีย์เวิร์ด yield
คีย์เวิร์ด yield บอกให้ Scala รวบรวมผลลัพธ์เป็นคอลเลกชันใหม่ชนิดเดียวกัน
หากไม่มี yield for-comprehension จะทำผลข้างเคียงกับแต่ละสมาชิกและคืนค่าเป็น Unit หรือถูกแปลงเป็น foreach
object Main {
def main(args: Array[String]): Unit = {
// No yield: side effect only
for (x <- List("a", "b")) println(x)
// With yield: builds a new List
val upper = for (x <- List("a", "b")) yield x.toUpperCase
println(upper)
}
}ตัวสร้างสองตัวจะกลายเป็น flatMap + map
เมื่อมีตัวสร้างสองตัวขึ้นไป ตัวสร้างด้านนอกจะกลายเป็น flatMap และตัวสร้างชั้นในสุดจะกลายเป็น map
for (x <- xs; y <- ys) yield f(x, y)- จะกลายเป็น
xs.flatMap(x => ys.map(y => f(x, y)))
object Main {
def main(args: Array[String]): Unit = {
val pairs = for {
x <- List(1, 2)
y <- List("a", "b")
} yield (x, y)
println(pairs)
}
}ดู flatMap ที่เทียบเท่ากัน
ในที่นี้ เราเขียนตรรกะเดียวกันทั้งสองรูปแบบ การพิสูจน์ว่าโค้ดทั้งสองเทียบเท่ากันแสดงให้เห็นว่า for-comprehension ไม่ได้เพิ่มความมหัศจรรย์ใด ๆ แต่ช่วยให้อ่านง่ายขึ้นเท่านั้น
object Main {
def main(args: Array[String]): Unit = {
val sugar = for {
x <- List(1, 2)
y <- List(10, 20)
} yield x + y
val desugared = List(1, 2).flatMap(x => List(10, 20).map(y => x + y))
println(sugar)
println(sugar == desugared)
}
}ทำไมตัวสร้างด้านนอกจึงใช้ flatMap
สมาชิกแต่ละตัวจากคอลเลกชันด้านนอกจะสร้างคอลเลกชันทั้งหมดของผลลัพธ์ด้านใน หากเราใช้ map กับตัวสร้างด้านนอก เราจะได้คอลเลกชันที่ซ้อนกัน เช่น List(List(...), List(...))
flatMap จะทำให้ลิสต์ที่ซ้อนกันเหล่านั้นแบนลงเป็นผลลัพธ์เดียวที่ไม่ซ้อนกัน
object Main {
def main(args: Array[String]): Unit = {
val nested = List(1, 2).map(x => List(10, 20).map(y => x + y))
val flat = List(1, 2).flatMap(x => List(10, 20).map(y => x + y))
println(nested)
println(flat)
}
}for ที่ไม่มี yield คือ foreach
ลูป for ที่ไม่มี yield จะถูกแปลงเป็น foreach โดยทำงานกับส่วนคำสั่งเพื่อให้เกิดผลข้างเคียง และคืนค่าเป็น Unit
for (x <- xs) doSomething(x)- จะกลายเป็น
xs.foreach(x => doSomething(x))
object Main {
def main(args: Array[String]): Unit = {
val r: Unit = for (x <- List(1, 2, 3)) print(x + " ")
println()
println("Return type is Unit")
}
}ชนิดผลลัพธ์ตามตัวสร้างแรก
ชนิดของผลลัพธ์จะกำหนดโดยคอลเลกชันของตัวสร้างแรก for ที่ทำงานกับ List จะให้ผลเป็น List ทำงานกับ Set จะให้ผลเป็น Set และทำงานกับ Option จะให้ผลเป็น Option
object Main {
def main(args: Array[String]): Unit = {
val fromList = for (x <- List(1, 2, 2, 3)) yield x
val fromSet = for (x <- Set(1, 2, 2, 3)) yield x
println(fromList)
println(fromSet)
}
}การผูกค่าด้วย =
ภายใน for-comprehension คุณสามารถผูกค่าระหว่างทางด้วย = วิธีนี้ช่วยหลีกเลี่ยงการคำนวณซ้ำและทำให้อ่านง่ายขึ้น
รูปแบบนี้จะถูกแปลงเป็น map ที่พาค่าเพิ่มเติมไปด้วยในทูเพิล
object Main {
def main(args: Array[String]): Unit = {
val result = for {
x <- List(1, 2, 3)
doubled = x * 2
} yield doubled + 1
println(result)
}
}ใช้ได้กับทุกชนิดที่มี map/flatMap
เนื่องจากการแปลงกลับนี้อาศัยเพียง map และ flatMap for-comprehension จึงใช้ได้กับชนิดข้อมูลใดก็ตามที่กำหนดเมธอดเหล่านี้ เช่น Option, Either, Try, Future และคลาสที่คุณสร้างเอง
object Main {
def main(args: Array[String]): Unit = {
val combined = for {
a <- Some(2)
b <- Some(3)
} yield a * b
println(combined)
}
}ประโยชน์สำคัญคืออ่านง่าย
ลองเปรียบเทียบลำดับการเรียก flatMap/map ที่ซ้อนกันลึก ๆ กับ for-comprehension ที่กระชับ ทั้งสองแบบคอมไพล์เป็นสิ่งเดียวกัน แต่แบบ for อ่านจากบนลงล่างได้เหมือนสูตรการทำงาน
object Main {
def main(args: Array[String]): Unit = {
val chained = List(1, 2).flatMap(a => List(3, 4).map(b => a * b))
val readable = for {
a <- List(1, 2)
b <- List(3, 4)
} yield a * b
println(chained == readable)
}
}ตรวจสอบความเข้าใจอย่างรวดเร็ว
คอมไพเลอร์จะแปลง for-comprehension ที่มีตัวสร้างสองตัวและมี yield อย่างไร
สรุปทบทวน
คุณได้เรียนรู้วิธีที่ for-comprehension ถูกแปลงกลับ:
- ตัวสร้างหนึ่งตัว +
yield→map - ตัวสร้างหลายตัว +
yield→flatMapสำหรับด้านนอก +mapสำหรับด้านใน - ไม่มี
yield→foreachที่คืนค่าเป็นUnit - การผูกค่า
val =จะเพิ่มค่าระหว่างทาง - ชนิดผลลัพธ์จะตามตัวสร้างแรก
ชนิดข้อมูลใดก็ตามที่มี map และ flatMap สามารถใช้ใน for-comprehension ได้
คำถามที่พบบ่อย
บทเรียน “การคลี่รูป for” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การคลี่รูป for” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Scala for Backend Engineering & Functional Programming ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Scala for Backend Engineering & Functional Programming มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การคลี่รูป for”
map และ flatMap คุณปฏิบัติ Scala for Backend Engineering & Functional Programming ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Scala for Backend Engineering & Functional Programming หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Scala for Backend Engineering & Functional Programming บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน
บทเรียน “การคลี่รูป for” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Scala for Backend Engineering & Functional Programming นี้ได้ไหม
ได้ บทเรียน Scala for Backend Engineering & Functional Programming ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ