Lambda: คืออะไร ไวยากรณ์ และการใช้งานใน Kotlin

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-06-23 เวลาอ่าน: 7 นาที

Lambda คือฟังก์ชันนิรนามที่แสดงเป็นนิพจน์ขนาดกะทัดรัด { อาร์กิวเมนต์ -> เนื้อหา } ใน Kotlin แลมบ์ดาเป็นวิธีหลักในการส่งผ่านพฤติกรรมไปยังฟังก์ชันลำดับสูง โดยให้ไวยากรณ์ที่กระชับโดยไม่ต้องประกาศฟังก์ชันแยกต่างหาก ตาม เอกสารของ Kotlin (2026) มากกว่า 70% ของฟังก์ชันลำดับสูงในโครงการทั่วไปถูกเรียกใช้ด้วยแลมบ์ดา Lambda ช่วยให้เขียนโค้ดในรูปแบบฟังก์ชันด้วยสัญญาณรบกวนทางไวยากรณ์น้อยที่สุด

ประเด็นสำคัญ

  • Lambda — ฟังก์ชันนิรนามในไวยากรณ์ { args -> body } ไม่มีชื่อ
  • it โดยนัย แทนที่อาร์กิวเมนต์เดียวของแลมบ์ดา ทำให้การเขียนง่ายขึ้น
  • Trailing lambda — การย้ายแลมบ์ดาตัวสุดท้ายออกนอกวงเล็บเรียกใช้เพื่อความอ่านง่าย
  • การปิด (closure) — แลมบ์ดาสามารถเข้าถึงตัวแปรจากขอบเขตภายนอก
  • ชนิดฟังก์ชัน (T) -> R กำหนดลายเซ็นของแลมบ์ดาและถูกตรวจสอบโดยคอมไพเลอร์

Lambda คืออะไร?

Lambda (นิพจน์ lambda) คือฟังก์ชันนิรนามที่กำหนดเป็นนิพจน์แทนการประกาศ คำนี้มีที่มาจากแคลคูลัสแลมบ์ดาของ Alonzo Church (1936) ในการเขียนโปรแกรม แลมบ์ดาคือบล็อกของโค้ดที่สามารถส่งผ่านเป็นค่า เก็บไว้ในตัวแปร และเรียกใช้ในภายหลัง ใน Kotlin แลมบ์ดาจะอยู่ในวงเล็บปีกกา { } เสมอ โดยอาร์กิวเมนต์จะถูกแยกจากเนื้อหาด้วยลูกศร ->

แลมบ์ดาแตกต่างจากฟังก์ชันปกติตรงที่ไม่มี ชื่อ และคีย์เวิร์ด fun ซึ่งช่วยให้ประกาศพฤติกรรมได้โดยตรงที่จุดใช้งาน โดยไม่ทำให้โค้ดรกด้วยการประกาศเพิ่มเติม คอมไพเลอร์ Kotlin อนุมานชนิดของอาร์กิวเมนต์จากบริบท ดังนั้นในหลายกรณีจึงสามารถละเว้นชนิดได้ แลมบ์ดาคือน้ำตาลทางไวยากรณ์เหนือชนิดฟังก์ชัน (T) -> R: ทุกแลมบ์ดามีชนิดฟังก์ชันที่สอดคล้องกัน

การใช้งานหลักของแลมบ์ดาใน Kotlin คือการส่งต่อไปยัง ฟังก์ชันลำดับสูง ไลบรารีมาตรฐานใช้แลมบ์ดาทุกที่: filter { it > 0 }, map { it.uppercase() }, forEach { println(it) } แลมบ์ดายังใช้สำหรับตัวฟังเหตุการณ์ คอลแบ็ก และตัวกำหนดค่า object ผ่าน apply และ run ทำให้โค้ดเป็นเชิงประกาศมากขึ้นเมื่อเทียบกับคลาสนิรนาม

ไวยากรณ์นิพจน์ lambda ใน Kotlin

รูปแบบเต็มของ นิพจน์ lambda ใน Kotlin: { อาร์กิวเมนต์ -> เนื้อหา_lambda } อาร์กิวเมนต์จะถูกเรียงคั่นด้วยเครื่องหมายจุลภาค ตามด้วยลูกศรและเนื้อหา — หนึ่งนิพจน์หรือมากกว่า หากเนื้อหามีหลายบรรทัด นิพจน์สุดท้ายจะกลายเป็นค่าที่ส่งกลับ หากฟังก์ชันรับแลมบ์ดาเป็นอาร์กิวเมนต์สุดท้าย สามารถย้ายออกนอกวงเล็บเรียกใช้ได้

kotlin
val sum: (Int, Int) -> Int = { a, b -> a + b }

// ชนิดที่อนุมานจากบริบท
val sumShort = { a: Int, b: Int -> a + b }

// การเรียก Lambda
val result = sum(5, 3)  // 8
println(result)

ตัวแปร sum ถูกประกาศด้วยชนิดฟังก์ชันที่ชัดเจน (Int, Int) -> Int และเริ่มต้นด้วยแลมบ์ดา { a, b -> a + b } สำหรับ sumShort ชนิดถูกระบุภายในแลมบ์ดาและชนิดตัวแปรถูกอนุมาน ทั้งสองรูปแบบเทียบเท่ากัน การเรียกใช้แลมบ์ดาไม่แตกต่างจากการเรียกใช้ฟังก์ชันปกติ — โดยใช้ไวยากรณ์ sum(5, 3) แลมบ์ดาที่ไม่มีอาร์กิวเมนต์เขียนเป็น { body } มีหนึ่งอาร์กิวเมนต์ — { it -> it * 2 } หรือเพียง { it * 2 }

it โดยนัยและการละเว้นอาร์กิวเมนต์

เมื่อแลมบ์ดารับอาร์กิวเมนต์เพียงหนึ่งตัว Kotlin จะให้ชื่อโดยนัย it ซึ่งช่วยลดความจำเป็นในการประกาศอาร์กิวเมนต์ทางด้านซ้าย นักพัฒนาเขียนเพียงเนื้อหาแลมบ์ดา โดยใช้ it เพื่อเข้าถึงพารามิเตอร์เดียว ไวยากรณ์นี้สะดวกเป็นพิเศษในห่วงโซ่การประมวลผลคอลเล็กชัน where it หมายถึงองค์ประกอบปัจจุบัน

kotlin
val numbers = listOf(1, 2, 3, 4, 5)

// ชื่อพารามิเตอร์ที่ชัดเจน
val squaredExplicit = numbers.map { n -> n * n }

// it โดยนัย
val squared = numbers.map { it * it }

// การกรองด้วย it
val even = numbers.filter { it % 2 == 0 }

println(squared) // [1, 4, 9, 16, 25]

ในตัวอย่าง map { it * it } ใช้ it แทนการประกาศ n -> Kotlin กำหนด it โดยอัตโนมัติสำหรับพารามิเตอร์แลมบ์ดาตัวเดียว หากแลมบ์ดารับสองอาร์กิวเมนต์ขึ้นไป it จะไม่ถูกสร้าง — ต้องประกาศพารามิเตอร์ทั้งหมดอย่างชัดเจน เพื่อความอ่านง่ายของแลมบ์ดาที่ซ้อนกัน ควรตั้งชื่อพารามิเตอร์ที่มีความหมายและใช้ it เฉพาะในเพรดิเคตสั้นๆ บรรทัดเดียว

Trailing lambda และแลมบ์ดาหลายบรรทัด

Trailing lambda คือคุณสมบัติทางไวยากรณ์ของ Kotlin ที่อนุญาตให้ย้ายอาร์กิวเมนต์แลมบ์ดาตัวสุดท้ายออกนอกวงเล็บเรียกใช้ฟังก์ชัน ทำให้โค้ดดูเหมือนโครงสร้างภาษาที่มีอยู่ในตัว หากแลมบ์ดาเป็นอาร์กิวเมนต์เดียว สามารถละเว้นวงเล็บได้ทั้งหมด วิธีนี้ถูกใช้อย่างแข็งขันในไลบรารีมาตรฐานและ DSL

kotlin
// การเรียกมาตรฐาน
thread(block = {
    println("สวัสดีจากเธรด")
})

// เวอร์ชัน trailing lambda
thread {
    println("สวัสดีจากเธรด")
}

// ทำซ้ำกับ trailing lambda
repeat(3) { index ->
    println("การวนซ้ำ $index")
}

// เรียกใช้กับแลมบ์ดาหลายบรรทัด
val config = run {
    val host = "localhost"
    val port = 8080
    "$host:$port"
}

ฟังก์ชัน thread รับ Runnable เป็นอาร์กิวเมนต์สุดท้าย ด้วย trailing lambda ทำให้สามารถส่งแลมบ์ดานอกวงเล็บได้ ซึ่งมองเห็นเป็นบล็อกโค้ด ฟังก์ชัน repeat รับจำนวนการวนซ้ำและแลมบ์ดาพร้อมดัชนี run เป็นตัวอย่างของฟังก์ชันลำดับสูงที่แลมบ์ดาหลายบรรทัดคำนวณค่าที่ส่งกลับโดยนิพจน์สุดท้าย วงเล็บรอบ run() สามารถละเว้นได้หากแลมบ์ดาเป็นอาร์กิวเมนต์เดียว

การจับตัวแปร (closure) ในแลมบ์ดา

การจับตัวแปร (closure) คือความสามารถของแลมบ์ดาในการเข้าถึงตัวแปรที่ประกาศในขอบเขตภายนอก ใน Kotlin แลมบ์ดาสามารถอ่านและแก้ไขตัวแปร var รวมถึงอ่านตัวแปร val จากบริบทโดยรอบ ตัวแปรที่ถูกจับจะถูกเก็บไว้กับแลมบ์ดาตลอดวงจรชีวิตของมัน ทำให้สามารถสร้างฟังก์ชันที่มีสถานะได้

kotlin
fun makeCounter(): () -> Int {
    var count = 0
    return {
        count++  // จำนวนการจับ
    }
}

fun main() {
    val counter = makeCounter()
    println(counter()) // 0
    println(counter()) // 1
    println(counter()) // 2
}

ฟังก์ชัน makeCounter ประกาศตัวแปรเฉพาะที่ count และส่งคืนแลมบ์ดา { count++ } แม้ว่า makeCounter จะทำงานเสร็จสิ้นแล้ว แลมบ์ดาที่ส่งคืนยังคงเก็บการอ้างอิงถึง count ผ่านการปิด แต่ละครั้งที่เรียก counter() จะเพิ่มและส่งคืนค่าปัจจุบัน กลไก closure เป็นพื้นฐานของ currying โรงงานฟังก์ชัน และ memoization สิ่งสำคัญคือต้องจำว่าการจับตัวแปรที่เปลี่ยนแปลงได้อาจนำไปสู่พฤติกรรมที่ไม่คาดคิดในการทำงานพร้อมกัน

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

แลมบ์ดาสามารถมี return ได้หรือไม่?

Lambda ไม่สนับสนุน return แบบไม่มีเงื่อนไข — return ที่ไม่มีป้ายกำกับจะส่งคืนการควบคุมไปยังฟังก์ชันภายนอก หากต้องการออกจากแลมบ์ดา ให้ใช้ return@label โดยที่ label คือชื่อของฟังก์ชันลำดับสูงที่แลมบ์ดาถูกส่งไป

ความแตกต่างระหว่างแลมบ์ดาและฟังก์ชันนิรนามคืออะไร?

ฟังก์ชันนิรนาม เขียนเป็น fun(a: Int): Int { return a * 2 } และสนับสนุน return โดยไม่มีป้ายกำกับ แลมบ์ดา { a -> a * 2 } สั้นกว่าในไวยากรณ์แต่ต้องใช้ return@label สำหรับการออกก่อนกำหนด

จะส่งแลมบ์ดาเป็นอาร์กิวเมนต์โดยไม่มีลูกศรได้อย่างไร?

หากแลมบ์ดาไม่รับอาร์กิวเมนต์ ลูกศรจะถูกละเว้น: { body() } หากรับหนึ่งอาร์กิวเมนต์แต่ไม่ได้ใช้ ให้เขียน { _ -> body() } ด้วยขีดล่างเพื่อละเว้นพารามิเตอร์

แลมบ์ดาสร้างออบเจกต์ใหม่ทุกครั้งหรือไม่?

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

ทำไมจึงไม่สามารถใช้ return โดยตรงในแลมบ์ดา?

Return ใน Kotlin คือตัวดำเนินการกระโดดที่เป็นของฟังก์ชันที่ใกล้ที่สุดที่ประกาศด้วย fun แลมบ์ดาไม่ใช่ฟังก์ชัน (fun) แต่เป็นนิพจน์ ดังนั้น return ภายในแลมบ์ดาที่ไม่มีป้ายกำกับจะถูกถือว่าเป็นการส่งกลับจากฟังก์ชันภายนอกที่ครอบอยู่

สรุป

  • Lambda — ฟังก์ชันนิรนามในไวยากรณ์ { args -> body } ส่งเป็นค่าไปยังฟังก์ชันลำดับสูง
  • it โดยนัย แทนที่อาร์กิวเมนต์เดียว ทำให้โค้ดกระชับขึ้นในเพรดิเคตสั้นๆ
  • Trailing lambda ย้ายแลมบ์ดาตัวสุดท้ายออกนอกวงเล็บเรียกใช้ อ่านเหมือนบล็อกโค้ด
  • การปิด (closure) อนุญาตให้แลมบ์ดาเข้าถึงตัวแปรจากบริบทภายนอกหลังจากฟังก์ชันที่ครอบเสร็จสิ้น
  • ชนิดฟังก์ชัน (T) -> R กำหนดลายเซ็นแลมบ์ดาพร้อมการตรวจสอบในเวลาคอมไพล์
  • ฟังก์ชัน inline ขจัดการสร้างคลาสนิรนามสำหรับแลมบ์ดา เพิ่มประสิทธิภาพในลูป
  • แลมบ์ดาหลายบรรทัด ส่งกลับค่าของนิพจน์สุดท้าย รองรับการคำนวณที่ซับซ้อนโดยไม่ต้องประกาศฟังก์ชันแยก

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม