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

@DslMarker: ป้องกันการรั่วไหลของตัวรับ

ใช้คำอธิบายประกอบ @DslMarker เพื่อบังคับใช้กฎการซ้อน DSL ตั้งแต่เวลาคอมไพล์

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

ปัญหาตัวรับรั่วไหล

ใน DSL ที่ซ้อนกัน แลมบ์ดาของตัวสร้างภายในอาจเข้าถึงสมาชิกจากตัวรับภายนอกได้โดยไม่ตั้งใจ ตัวอย่างเช่น ภายในบล็อก td { } คุณอาจเรียกใช้ tr { } จากขอบเขตตารางภายนอก ซึ่งแทบไม่เคยเป็นสิ่งที่ต้องการ

ลักษณะของการรั่วไหล

หากไม่มี @DslMarker คอมไพเลอร์จะอนุญาตให้เรียกใช้ฟังก์ชันจากขอบเขตภายนอกจากแลมบ์ดาภายในใด ๆ ได้ ซึ่งทำให้การใช้ DSL สับสนและเกิดข้อผิดพลาดได้ง่าย:

// Without @DslMarker — this compiles but is wrong:
html {
    body {
        table {
            tr {                // outer scope leaks in
                tr {  }         // calling tr inside tr — nonsensical
            }
        }
    }
}

แนะนำ @DslMarker

@DslMarker คือเมทาแอนโนเทชันที่คุณนำไปใช้กับคลาสแอนโนเทชันของคุณเอง คลาสตัวสร้างใด ๆ ที่มีแอนโนเทชัน DSL ของคุณจะมีตัวรับโดยนัยถูกซ่อนในแลมบ์ดาที่ซ้อนกันและใช้แอนโนเทชัน DSL เดียวกัน

@DslMarker
annotation class HtmlDsl

@HtmlDsl
class Table

@HtmlDsl
class Tr

การซ่อนตัวรับโดยนัยทำงานอย่างไร

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

@DslMarker
annotation class HtmlDsl

@HtmlDsl class Html
@HtmlDsl class Body
@HtmlDsl class Div

ตัวอย่างฉบับเต็มด้วย @DslMarker

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

@DslMarker
annotation class MyCfgDsl

@MyCfgDsl
class ServerBuilder {
    var port: Int = 8080
    fun database(block: DbBuilder.() -> Unit) { /*...*/ }
}

@MyCfgDsl
class DbBuilder {
    var url: String = ""
    // Cannot call ServerBuilder.port here — compiler error
}

หลีกเลี่ยงข้อจำกัดด้วย this@

หากจำเป็นต้องเข้าถึงตัวรับภายนอกจากแลมบ์ดาภายในจริง ๆ ให้ใช้การอ้างอิง this@OuterClass ที่มีป้ายกำกับ วิธีนี้ชัดเจนและตั้งใจใช้ ต่างจากการรั่วไหลโดยไม่ตั้งใจ

fun ServerBuilder.database(block: DbBuilder.() -> Unit) {
    val db = DbBuilder()
    db.block()
    val serverPort = this@ServerBuilder.port  // explicit outer access
}

@DslMarker กับ DSL หลายชุด

DSL แต่ละชุดควรใช้แอนโนเทชัน @DslMarker คนละรายการ DSL สองชุดที่ไม่เกี่ยวข้องกันและใช้เครื่องหมายต่างกันจะไม่รบกวนกัน แม้จะซ้อนกันอยู่

@DslMarker annotation class HtmlDsl
@DslMarker annotation class GradleDsl
// HtmlDsl and GradleDsl receivers do not hide each other

การใช้กับตัวสร้างและตัวรับ

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

การรองรับจากสภาพแวดล้อมการพัฒนา

IntelliJ IDEA และ Android Studio จะแสดงการเข้าถึงตัวรับภายนอกเป็นข้อผิดพลาดทันทีเมื่อใช้ @DslMarker ทำให้ได้รับข้อมูลป้อนกลับแบบเรียลไทม์ขณะสร้างหรือใช้งาน DSL

การออกแบบเพื่อความปลอดภัย

การออกแบบ DSL ที่ดีจะจับคู่คลาสตัวสร้างแต่ละคลาสกับ @DslMarker แม้จะเพิ่มแอนโนเทชันเพียงเล็กน้อย แต่ช่วยให้การใช้ DSL สะดวกขึ้นอย่างมากและป้องกันข้อผิดพลาดได้หลายประเภทสำหรับผู้ใช้ DSL

การใช้งานในไลบรารีมาตรฐาน

@DslMarker ของ Kotlin เองถูกใช้ใน kotlinx.html, DSL สำหรับการกำหนดเส้นทางของ Ktor, สคริปต์ Gradle Kotlin และตัวสร้าง buildMap/buildList นี่เป็นเครื่องมือพื้นฐานในชุดเครื่องมือ DSL ที่จริงจังทุกชุด

ตรวจสอบความเข้าใจ

@DslMarker ป้องกันอะไร?

สรุป: @DslMarker

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

  • หากไม่มี @DslMarker ตัวรับภายนอกจะรั่วไหลเข้าไปในแลมบ์ดา DSL ภายใน
  • กำหนดคลาสแอนโนเทชันที่มีเมทาแอนโนเทชัน แล้วนำไปใช้กับคลาสตัวสร้างทั้งหมดใน DSL
  • แลมบ์ดาที่ซ้อนกันและใช้เครื่องหมายเดียวกันจะไม่สามารถเรียกสมาชิกจากขอบเขตภายนอกโดยไม่ตั้งใจ
  • ใช้ this@OuterClass เมื่อต้องการเข้าถึงขอบเขตภายนอกจริง ๆ

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

บทเรียน “@DslMarker: ป้องกันการรั่วไหลของตัวรับ” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “@DslMarker: ป้องกันการรั่วไหลของตัวรับ”

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

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

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

บทเรียน “@DslMarker: ป้องกันการรั่วไหลของตัวรับ” ใช้เวลานานแค่ไหน

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

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

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

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

  1. Lambda พร้อมตัวรับ: รากฐานของ DSL
  2. @DslMarker: ป้องกันการรั่วไหลของตัวรับ
  3. สร้าง DSL สำหรับ HTML/การกำหนดค่าที่ปลอดภัยด้านชนิด
  4. ทดสอบและพัฒนา DSL โดยไม่ทำลายผู้ใช้
← กลับไปที่ Kotlin Academy