Kotlin Academy · บทเรียน

ควรใช้แต่ละแบบเมื่อใด

ข้อแลกเปลี่ยน

บทเรียน 4 จาก 413 ขั้นตอน

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

เครื่องมือสองชนิด งานต่างกัน

ฟังก์ชันอินฟิกซ์เน้นเรื่องความอ่านง่าย ส่วนฟังก์ชันเรียกซ้ำแบบหางเน้นการเรียกซ้ำที่ปลอดภัยและมีประสิทธิภาพ ทั้งสองอย่างแก้ปัญหาคนละประเภทกัน

infix fun Int.add(o: Int) = this + o

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

fun main() {
    println(2 add 3)
    println(sum(10))
}

เลือกอินฟิกซ์สำหรับเอพีไอที่อ่านได้อย่างลื่นไหล

เลือกใช้อินฟิกซ์เมื่อการเรียกใช้จะอ่านได้ดีขึ้นโดยไม่ต้องมีจุดและวงเล็บ โดยเฉพาะใน DSL และการสร้างคู่ข้อมูล

fun main() {
    val pair = "id" to 100
    println(pair)
}

เลือก tailrec สำหรับการเรียกซ้ำลึก

ใช้ tailrec เมื่ออัลกอริทึมแบบเรียกซ้ำอาจเรียกซ้ำลึกจนทำให้สแตกโอเวอร์โฟลว์

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

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

ข้อแลกเปลี่ยนของอินฟิกซ์

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

infix fun Int.scaledBy(f: Int) = this * f

fun main() {
    println(5 scaledBy 3)
}

ข้อแลกเปลี่ยนของการเรียกซ้ำแบบหาง

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

tailrec fun product(n: Int, acc: Long = 1): Long =
    if (n <= 1) acc else product(n - 1, acc * n)

fun main() {
    println(product(6))
}

เมื่อลูปเรียบง่ายกว่า

หากลูป for หรือ while ทั่วไปอ่านเข้าใจได้ชัดกว่าการเรียกซ้ำแบบหาง ควรเลือกลูป การเรียกซ้ำเป็นเครื่องมือ ไม่ใช่ข้อกำหนด

fun sumLoop(n: Int): Int {
    var total = 0
    for (i in 1..n) total += i
    return total
}

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

เมื่อการเรียกใช้ที่มีชื่อชัดเจนกว่า

หากชื่ออินฟิกซ์ไม่ได้สื่อถึงความสัมพันธ์แบบไบนารีอย่างชัดเจน การเรียกใช้เมธอดทั่วไปจะสื่อเจตนาได้ดีกว่า

data class Temp(val c: Int) {
    fun isWarmerThan(o: Temp) = c > o.c
}

fun main() {
    println(Temp(30).isWarmerThan(Temp(20)))
}

การใช้ทั้งสองอย่างร่วมกัน

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

infix fun Int.upto(n: Int) = (this..n).toList()

tailrec fun last(list: List<Int>): Int =
    if (list.size == 1) list[0] else last(list.drop(1))

fun main() {
    println(last(1 upto 5))
}

รายการตรวจสอบความอ่านง่าย

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

fun main() {
    val r = (1..5).sum()
    println(r)
}

หมายเหตุด้านประสิทธิภาพ

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

tailrec fun pow(base: Int, exp: Int, acc: Long = 1): Long =
    if (exp == 0) acc else pow(base, exp - 1, acc * base)

fun main() {
    println(pow(2, 10))
}

สรุปการตัดสินใจ

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

infix fun String.joinWith(o: String) = "$this-$o"

fun main() {
    println("a" joinWith "b")
}

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

ทดสอบความเข้าใจเกี่ยวกับเวลาที่ควรใช้คุณสมบัติแต่ละอย่าง

สรุปทบทวน

คุณได้เรียนรู้เวลาที่ควรใช้แต่ละอย่าง:

  • ใช้ infix สำหรับการเรียกใช้แบบไบนารีที่อ่านได้อย่างลื่นไหลและอ่านง่าย รวมถึง DSL
  • ใช้ tailrec สำหรับการเรียกซ้ำที่ต้องรองรับขนาดการทำงานได้โดยไม่เกิดสแตกโอเวอร์โฟลว์
  • เลือกลูปหรือฟังก์ชันที่มีชื่อทั่วไปเมื่ออ่านเข้าใจได้ชัดเจนกว่า
  • คุณสมบัติทั้งสองไม่ขึ้นต่อกันและสามารถใช้ร่วมกันได้
infix fun Int.by(o: Int) = this * o
tailrec fun dec(n: Int): Int = if (n == 0) 0 else dec(n - 1)

fun main() {
    println(3 by 4)
    println(dec(1000))
}
เริ่มต้นได้ฟรี

เรียนรู้ Kotlin ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
51
บทเรียน
203

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

บทเรียน “ควรใช้แต่ละแบบเมื่อใด” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “ควรใช้แต่ละแบบเมื่อใด”

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

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

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

บทเรียน “ควรใช้แต่ละแบบเมื่อใด” ใช้เวลานานแค่ไหน

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

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

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

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

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