Higher-order function: คืออะไร ลักษณะและตัวอย่างใน Kotlin

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

Higher-order function คือฟังก์ชันที่รับฟังก์ชันอื่นเป็นพารามิเตอร์หรือคืนฟังก์ชันเป็นผลลัพธ์ใน Kotlin ฟังก์ชันเป็นพลเมิงของคลาสแรก: สามารถเก็บในตัวแปร ส่งเป็นอาร์กิวเมนต์ และคืนได้ ตาม เอกสาร Kotlin (2026) higher-order functions ช่วยลดการทำซ้ำโค้ดโดยเฉลี่ย 30% เมื่อเทียบกับวิธีการแบบิมเพราทีฟ Higher-order function เป็นแนวคิดพื้นฐานของรูปแบบฟังก์ชันในการพัฒนาสมัยใหม่

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

  • Higher-order function — ฟังก์ชันที่รับฟังก์ชันอื่นเป็นพารามิเตอร์หรือคืนหนึ่งฟังก์ชัน
  • ชนิดฟังก์ชัน (T) -> R — พื้นฐานของการประกาศพารามิเตอร์ฟังก์ชันในลายเซ็น
  • นิพจน์ lambda — วิธีการส่งฟังก์ชันไปยัง higher-order function แบบกะทัดรัด
  • การ\u0e2a่งพฤติกรรม ช่วยให้สามารถกำหนดพารามิเตอร์การทำงานโดยไม่ต้องใช้การสืบทอดและอินเทอร์เฟส
  • การคืนฟังก์ชัน จาก higher-order function ใช้สำหรับโรงงานและการปิดล้อม

Higher-order function คืออะไร?

Higher-order function คือฟังก์ชันที่มีอย่างน้อยหนึ่งในสองคุณลักษณะ: การรับฟังก์ชันอื่นเป็นอาร์กิวเมนต์หรือการคืนฟังก์ชันเป็นผลลัพธ์ ในคณิตศาสตร์ ฟังก์ชันเหล่านี้เรียกว่าฟังก์ชันนัลหรือตัวดำเนินการ ในการเขียนโปรแกรม ฟังก์ชันเหล่านี้ปรากฎตั้งแต่ปี 1958 ใน Lisp และกลายเป็นส่วนบังคับของภาษาสมัยใหม่ทั้งหมด — JavaScript, Python, Swift, Kotlin, Scala และ Haskell Higher-order function ช่วยให้สามารถทำนามธรรมจากการดำเนินการเฉพาะและ ส่งพฤติกรรมเป็นค่า

ความแตกต่างหลักระหว่าง higher-order function กับฟังก์ชันทั่วไปคือการมีพารามิเตอร์ที่มี ชนิดฟังก์ชัน หรือค่าฟังก์ชันที่คืนมา ใน Kotlin ชนิดฟังก์ชันเขียนเป็น (ParamType) -> ReturnType ตัวอย่าง ชนิด (Int) -> String หมายถึงฟังก์ชันที่รับ Int และคืน String ชนิด () -> Unit หมายถึงฟังก์ชันที่ไม่มีพารามิเตอร์และไม่คืนค่าที่มีประโยชน์ ระบบชนิดนี้เองที่ทำให้ higher-order functions มั่นความปลอดภัยด้านชนิด

สิ่งที่ตรงกันข้ามของ higher-order function คือ first-class function (ฟังก์ชันลำดับหนึ่ง) First-class function หมายความว่าสามารถใช้ฟังก์ชันเหมือนค่าอื่น ๆ: กำหนดค่าให้ตัวแปร เก็บในคอลเล็กชั่น ส่งเป็นอาร์กิวเมนต์ Higher-order function คือฟังก์ชันที่ใช้ first-class functions ในการรับหรือคืน Kotlin รองรับทั้งสองแนวคิดในระดับภาษาโดยไม่ต้องใช้ไลบรารีเพิ่มเติม

Higher-order function ทำงานใน Kotlin อย่างไร?

ใน Kotlin ฟังก์ชันใด ๆ ที่มีอย่างน้อยหนึ่งพารามิเตอร์ที่ประกาศด้วยชนิดฟังก์ชันหรือชนิดที่คืนเป็นชนิดฟังก์ชันจะถูกถือว่าเป็น higher-order function โดยอัตโนมัติ คอมไพเลอร์ไม่ต้องการอะไรพิเศษ — แค่ระบุ (T) -> R ในลายเซ็นก็พอ เมื่อเรียกฟังก์ชันดังกล่าว อาร์กิวเมนต์จะเป็นนิพจน์ lambda การอ้างอิงไปยังฟังก์ชันที่มีอยู่แล้วผ่าน :: หรือค่าฟังก์ชันที่เก็บไว้ในตัวแปร

kotlin
fun operate(a: Int, b: Int, op: (Int, Int) -> Int): Int {
    return op(a, b)
}

fun main() {
    val sum = operate(10, 20) { x, y -> x + y }
    println(sum) // 30
}

ในรายการ ฟังก์ชัน operate รับจำนวนเต็มสองตัวและพารามิเตอร์ op ชนิด (Int, Int) -> Int ตัวฟังก์ชันเรียกการดำเนินการที่ส่งมาในบรรทัดเดียว ใน main การเรียก operate ส่ง lambda { x, y -> x + y } — Kotlin วางไว้หลังวงเล็บโดยใช้ไวยากรณ์ trailing lambda หาก lambda เป็นอาร์กิวเมนต์สุดท้าย จะสามารถย้ายไปนอกวงเล็บได้อย่างสมบูรณ์ ซึ่งช่วยให้อ่านโซ่โฟร์เชนของสายโส้การเรียกง่ายขึ้น

ภายใต้ Kotlin คอมไพล์ higher-order functions ผ่าน อินเทอร์เฟส Function (Function2 สำหรับสองพารามิเตอร์) แต่ละ lambda กลายเป็นคลาสนิรนามที่ใช้งานอินเทอร์เฟส FunctionN ที่สอดคล้องกัน ซึ่งหมายความว่าการสร้าง lambda ต้องจัดสรรอบเจกส์สำหรับแต่ละการดำเนินการ เพื่อลดโอเวอร์เฮ็ด Kotlin รองรัฟังก์ชัน inline ซึ่งแทนที่ตัวของ higher-order function ที่ตำแหน่งที่เรียก ซึ่งช่วยขจัดการสร้างคลาสนิรนาม

ฟังก์ชันเป็นพารามิเตอร์: การส่งพฤติกรรม

การส่งฟังก์ชันเป็น อาร์กิวเมนต์ เป็นรูปแบบที่พบบ่อยที่สุดของการใช้ higher-order functions แทนที่จะสร้างลำดับชั้นคลาสโดยใช้เมธอดพอลิมอร์ฟิสม์ นักพัฒนาสามารถส่งพฤติกรรมที่ต้องการไปยังจุดที่ใช้งานโดยตรง ซึ่งเป็นการใช้หลักเปิดปิด (Open/Closed Principle) โดยไม่ต้องใช้การสืบทอด: การดำเนินการใหม่จะถูกเพิ่มเป็น lambda ใหม่ ไม่ใช่คลาสย่อยใหม่

สำหรับฟังก์ชันที่สามารถเป็น null ได้ Kotlin ใช้ ชนิด ((T) -> R)? โดยมีเครื่องหมายคำถามหลังวงเล็บ ฟังก์ชันดังกล่าวสามารถเรียกได้หลังจากการตรวจสอบ null หรือผ่านตัวดำเนินการ ?.invoke() ในกรณนี้ ลายเซ็นของ higher-order function ระบุอย่างชัดเจนว่าการส่งฟังก์ชันเป็นตัวเลือก — โค้ดที่เรียกสามารถลดอาร์กิวเมนต์ได้ ซึ่งมีประโยชน์สำหรับคอล์แบ็กและตัวจัดการอีเวนต์ที่มีพฤติกรรมเป็นตัวเลือก

kotlin
fun <T> List<T>.customFilter(
    predicate: (T) -> Boolean
): List<T> {
    val result = mutableListOf<T>()
    for (item in this) {
        if (predicate(item)) result.add(item)
    }
    return result
}

fun main() {
    val numbers = listOf(1, 2, 3, 4, 5)
    val even = numbers.customFilter { it % 2 == 0 }
    println(even) // [2, 4]
}

ฟังก์ชันส่วนขยาย customFilter รับพารามิเตอร์ predicate ของชนิดฟังก์ชัน (T) -> Boolean ภายในลูป มันเรียก predicate สำหรับแต่ละองค์ประกอบและรวบรวมองค์ประกอบที่ตรงกัน การเรียกใน main ส่ง lambda { it % 2 == 0 } โดยที่ it คือชื่อแฝงนิมนิพจน์ของพารามิเตอร์แต่งเดียวของ lambda ด้วย higher-order functions ทรรกฟิลเตอร์จึงแยกออกจากกลไการเดินข้ามคอลเล็กชั่นอย่างสมบูรณ์

ฟังก์ชันเป็นค่าที่คืน

Higher-order function สามารถ คืนฟังก์ชัน — รูปแบบนี้เรียกว่าโรงงานฟังก์ชันหรือตัวสร้างพฤติกรรม ฟังก์ชันที่คืนมาสามารถจับ (closure) ตัวแปรจากขอบเขตภายนอก โดยรักษาไว้ระหว่างการเรียกแต่ละครั้ง ซึ่งช่วยให้สามารถสร้างตัวจัดการที่กำหนดค่าได้และการดำเนินการเฉพาะทางโดยอิงตามแม่แบบทั่วไป

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

kotlin
fun makeMultiplier(factor: Int): (Int) -> Int {
    return { x -> x * factor }
}

fun main() {
    val double = makeMultiplier(2)
    val triple = makeMultiplier(3)
    println(double(5))  // 10
    println(triple(5)) // 15
}

ฟังก์ชัน makeMultiplier รับตัวประกอบ factor และคืน lambda { x -> x * factor } โดยที่ factor ถูกจับจากขอบเขตภายนอก (closure) แต่ละการเรียก makeMultiplier สร้างฟังก์ชันใหม่โดยมีค่า factor ของตนเอง ตัวแปร double และ triple เก็บฟังก์ชันที่คืนมาและสามารถเรียกได้หลายครั้ง รูปแบบนี้ใช้อย่างแพร่หลายในการกำหนดค่าไคลเอนต์ HTTP ตัวตกแต่ง แล้ะมิดเดิลแวร์

Higher-order function กับ lambda: ตัวอย่าง

การใช้ higher-order functions ร่วมกับ lambda ช่วยให้สามารถสร้างสายโส้การดำเนินการที่สามารถแสดงความหมายได้โดยไม่ต้องใช้ตัวแปรกลาง ไลบรารีมาตรฐานของ Kotlin มี higher-order functions อยู่หลายสิบตัว: let, run, apply, also, filter, map, flatMap, fold, reduce, forEach, groupBy และอื่น ๆ แต่ละตัวรับ lambda และดำเนินการแปลงข้อมูลโดยใช้มัน

kotlin
data class User(val name: String, val age: Int)

fun main() {
    val users = listOf(
        User("Alice", 25),
        User("Bob", 17),
        User("Charlie", 30)
    )

    val result = users
        .filter { it.age >= 18 }
        .map { it.name.uppercase() }
        .sorted()
    println(result) // [ALICE, CHARLIE]
}

ในตัวอย่าง สายโส้ของ higher-order functions สามตัวประมวลผลรายชื่อผู้ใช้ filter รับประโยจน์ เลือกเฉพาะผู้ใหญ่แล้ว map แปลงผู้ใช้แต่ละคนเป็นชื่อตัวพิมพ์ใหญ่ sorted เรียงเรียงผลลัพธ์จากน้อยไปมาก แต่ละการดำเนินการรับ lambda และ Kotlin รับประกันความปลอดภัยด้านชนิดในทุกขั้นตอน หากไม่มี higher-order functions จะต้องเขียนลูปที่มี if รายชื่อชั่วคราว และการเรียงลำดับด้วยตนเอง

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

Higher-order function แตกต่างจากฟังก์ชันทั่วไปอย่างไร?

Higher-order function รับฟังก์ชันอื่นเป็นพารามิเตอร์หรือคืนหนึ่งฟังก์ชัน ฟังก์ชันทั่วไปทำงานกับข้อมูลเท่านั้น — ตัวเลข, สตริง, อ็อบเจกต์ Higher-order function ทำงานกับพฤติกรรม โดยส่งตรรกะเป็นอาร์กิวเมนต์

Higher-order function สามารถเป็น inline ได้หรือไม่?

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

ชนิดฟังก์ชันของฟังก์ชันที่ไม่มีพารามิเตอร์คืออะไร?

ฟังก์ชันที่ไม่มีพารามิเตอร์และไม่มีค่าที่คืนมีชนิด () -> Unit ฟังก์ชันที่มีหนึ่งพารามิเตอร์ชนิด T และคืน R เขียนเป็น (T) -> R สำหรับสองพารามิเตอร์ — (T, U) -> R และเช่นนี้ไปจนถึง 22 อาร์กิวเมนต์

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

Lambda คือสัยลักษณ์ย่อ { args -> body } ส่วนฟังก์ชันนิรนามคือ fun(args): ReturnType { body } Lambda ไม่สามารถใช้ return โดยไม่มีฉลาก แต่ฟังก์ชันนิรนามสามารถใช้ได้ ทั้งสองสามารถส่งไปยัง higher-order function ได้

เมื่อใดควรหลีกเลี่ยง higher-order functions?

หลีกเลี่ยง higher-order functions ใน ลูปร้อน โดยไม่มี inline — แต่ละ lambda สร้างอ็อบเจกต์ สำหรับโค้ดที่ต้องการประสิทธิภาพสูง ใช้ inline fun อย่าใช้ lambda ที่ซ้อนกันลึกๆ มากเกินไป — สิ่งนี้จะลดความสามารถในการอ่าน

สรุป

  • Higher-order function — ฟังก์ชันที่รับฟังก์ชันอื่นเป็นพารามิเตอร์หรือคืนหนึ่งฟังก์ชัน; รากฐานของการเขียนโปรแกรมแบบฟังก์ชันใน Kotlin
  • ชนิดฟังก์ชัน (T) -> R ประกาศพารามิเตอร์ฟังก์ชันที่มีลายเซ็นที่ปลอดภัยด้านชนิด
  • นิพจน์ lambda — ไวยากรณ์กะทัดรัด { args -> body } สำหรับการส่งพฤติกรรม
  • ฟังก์ชัน inline ช่วยขจัดโอเวอร์เฮ็ดของการสร้างคลาสนิรนามสำหรับ lambda
  • โรงงานฟังก์ชัน คืนฟังก์ชันที่มีบริบท์ที่ถูกจัผ่านกลไกการปิดล้อม
  • สายโส้การดำเนินการ filter-map-sorted สร้างบน higher-order functions โดยไม่มีตัวแปรกลาง
  • ความปลอดภัยด้านชนิด ของ higher-order functions ถูกรับประกันโดยระบบชนิดฟังก์ชันของ Kotlin ในขณะแปลคอมไพล์

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

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

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

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