0Pricing
Kotlin Academy · บทเรียน

ฟังก์ชัน tailrec

เพิ่มประสิทธิภาพการเรียกซ้ำ

ฟังก์ชัน tailrec เป็นบทเรียน Kotlin Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Kotlin Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน

การเรียกซ้ำแบบหางคืออะไร

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

tailrec fun countdown(n: Int) {
    if (n < 0) return
    println(n)
    countdown(n - 1)
}

fun main() {
    countdown(3)
}

ตัวแก้ไขการเรียกซ้ำแบบหาง

เพิ่มตัวแก้ไข tailrec แล้วคอมไพเลอร์จะเขียนการเรียกซ้ำใหม่ให้เป็นการวนซ้ำ โดยใช้พื้นที่สแตกคงที่

tailrec fun sum(n: Int, acc: Int = 0): Int {
    if (n == 0) return acc
    return sum(n - 1, acc + n)
}

fun main() {
    println(sum(100))
}

รูปแบบ Accumulator

หากต้องการทำให้การเรียกซ้ำอยู่ในรูปแบบหาง ให้ส่งผลลัพธ์ต่อผ่านพารามิเตอร์ตัวสะสม เพื่อไม่ให้เหลือสิ่งใดต้องคำนวณหลังการเรียกใช้

tailrec fun factorial(n: Int, acc: Long = 1): Long {
    if (n <= 1) return acc
    return factorial(n - 1, acc * n)
}

fun main() {
    println(factorial(10))
}

เหตุผลที่การเรียกต้องเป็นการดำเนินการสุดท้าย

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

tailrec fun length(s: String, acc: Int = 0): Int {
    if (s.isEmpty()) return acc
    return length(s.drop(1), acc + 1)
}

fun main() {
    println(length("hello"))
}

ตัวอย่างโต้แย้งการเรียกซ้ำที่ไม่ใช่แบบหาง

ฟังก์ชันแฟกทอเรียลนี้ไม่ใช่การเรียกซ้ำแบบหาง เนื่องจากการคูณเกิดขึ้นหลังจากการเรียกส่งคืนค่า หากระบุ tailrec คอมไพเลอร์จะแสดงคำเตือน

fun badFactorial(n: Int): Long {
    if (n <= 1) return 1
    return n * badFactorial(n - 1)
}

fun main() {
    println(badFactorial(5))
}

การหลีกเลี่ยงสแตกโอเวอร์โฟลว์

การเรียกซ้ำลึกโดยไม่มี tailrec อาจทำให้โปรแกรมล้มเหลวได้ แต่เมื่อใช้ tailrec แม้อินพุตจะมีขนาดใหญ่ก็ยังทำงานด้วยพื้นที่สแตกคงที่

tailrec fun count(n: Int, acc: Int = 0): Int {
    if (n == 0) return acc
    return count(n - 1, acc + 1)
}

fun main() {
    println(count(100000))
}

การตรวจสอบโดยคอมไพเลอร์

หากคุณระบุ tailrec ให้ฟังก์ชัน แต่การเรียกไม่ได้อยู่ในตำแหน่งหาง คอมไพเลอร์จะแสดงคำเตือนและจะไม่ปรับโค้ดให้เหมาะสม โปรดเชื่อคำเตือนนั้น

tailrec fun gcd(a: Int, b: Int): Int {
    if (b == 0) return a
    return gcd(b, a % b)
}

fun main() {
    println(gcd(48, 18))
}

การเรียกซ้ำแบบหางกับลูป

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

tailrec fun powerOfTwo(n: Int, acc: Long = 1): Long {
    if (n == 0) return acc
    return powerOfTwo(n - 1, acc * 2)
}

fun main() {
    println(powerOfTwo(10))
}

พารามิเตอร์หลายตัว

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

tailrec fun fib(n: Int, a: Long = 0, b: Long = 1): Long {
    if (n == 0) return a
    return fib(n - 1, b, a + b)
}

fun main() {
    println(fib(20))
}

การกลับลำดับด้วย tailrec

ตัวสะสมสามารถค่อย ๆ สร้างผลลัพธ์ เช่น สตริงที่กลับลำดับแล้ว

tailrec fun reverse(s: String, acc: String = ""): String {
    if (s.isEmpty()) return acc
    return reverse(s.drop(1), s.first() + acc)
}

fun main() {
    println(reverse("kotlin"))
}

การค้นหาที่ใช้งานได้จริง

การค้นหาแบบวนซ้ำสามารถแปลงเป็นการเรียกซ้ำแบบหางได้อย่างตรงไปตรงมา

tailrec fun indexOf(list: List<Int>, target: Int, i: Int = 0): Int {
    if (i >= list.size) return -1
    if (list[i] == target) return i
    return indexOf(list, target, i + 1)
}

fun main() {
    println(indexOf(listOf(5, 6, 7), 7))
}

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

ทดสอบความเข้าใจเกี่ยวกับฟังก์ชัน tailrec

สรุปทบทวน

คุณได้เรียนรู้เรื่องฟังก์ชันเรียกซ้ำแบบหาง:

  • tailrec เปลี่ยนการเรียกซ้ำในตำแหน่งหางให้เป็นลูป เพื่อหลีกเลี่ยงสแตกโอเวอร์โฟลว์
  • การเรียกซ้ำต้องเป็นการดำเนินการสุดท้าย
  • ใช้พารามิเตอร์ตัวสะสมเพื่อให้ได้รูปแบบหาง
  • คอมไพเลอร์จะแสดงคำเตือนเมื่อไม่สามารถปรับฟังก์ชันให้เหมาะสมได้
tailrec fun sum(n: Int, acc: Int = 0): Int =
    if (n == 0) acc else sum(n - 1, acc + n)

fun main() {
    println(sum(50))
}

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

บทเรียน “ฟังก์ชัน tailrec” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “ฟังก์ชัน tailrec”

เพิ่มประสิทธิภาพการเรียกซ้ำ คุณปฏิบัติ Kotlin Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Kotlin Academy หรือไม่

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

บทเรียน “ฟังก์ชัน tailrec” ใช้เวลานานแค่ไหน

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

ฉันเขียนและรันโค้ดในบทเรียน Kotlin Academy นี้ได้ไหม

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

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

  1. ฟังก์ชัน Infix
  2. การสร้าง API ลักษณะ DSL
  3. ฟังก์ชัน tailrec
  4. ควรใช้แต่ละแบบเมื่อใด
← กลับไปที่ Kotlin Academy