Kotlin: شرح بناء DSL في كوتلن

آخر تحديث: 2026-08-26

DSL هي أكثر ميزات كوتلن تعبيراً — يُقرأ كملف إعدادات لكنه فعلياً كود كوتلن آمن الأنواع. يستخدمه تشارلي لبناء DSL لإعدادات الطلبات، مما يتيح للمستخدمين غير التقنيين تعريف قواعد الطلبات.

1. ما ستتعلمه


2. قصة مهندس حقيقية

(1) نقطة الألم: صيغات إعدادات غير آمنة

استخدمت قواعد طلبات تشارلي إعدادات YAML، لكن YAML لا يمتلك فحص أنواع — الأخطاء الإملائية والحقول المفقودة تظهر فقط وقت التشغيل. هذا تسبب في 2-3 حوادث إنتاج شهرياً من أخطاء الإعدادات.

(2) حل DSL في كوتلن

KOTLIN
// YAML: لا أمان أنواع، أخطاء وقت التشغيل
order:
  customer: Alice
  items:
    - sku: ABC
      qty: three  // خطأ إملائي! يجب أن يكون 3

// DSL كوتلن: آمن الأنواع، أخطاء وقت الترجمة
order {
    customer = "Alice"
    items {
        item { sku = "ABC"; qty = 3 }  // فحص أنواع وقت الترجمة!
    }
}

DSL كوتلن = مرونة الإعدادات + أمان الأنواع في الكود. المترجم يلتقط أخطاء الإعدادات وقت الترجمة.


3. مستقبلات لامبدا

(1) لامبدا مع مستقبل

KOTLIN
// لامبدا عادية: معامل
val greet: (String) -> Unit = { name -> println("Hello, $name") }

// لامبدا مع مستقبل: 'this' يشير للمستقبل
val greet2: String.() -> Unit = { println("Hello, $this") }

// الاستخدام
greet2("Alice")          // Hello, Alice
"Alice".greet2()         // Hello, Alice (استدعاء شبيه بالامتداد)

(2) with / apply / run

KOTLIN
val order = Order()

// with: تنفيذ كتلة مع مستقبل، إرجاع نتيجة الكتلة
val summary = with(order) {
    id = "ORD-001"
    total = 299.99
    "Order $id created"  // قيمة الإرجاع
}

// apply: تنفيذ كتلة مع مستقبل، إرجاع المستقبل نفسه
val configured = order.apply {
    id = "ORD-001"       // 'this' هو order
    total = 299.99
}  // يرجع order

// run: تنفيذ كتلة مع مستقبل، إرجاع نتيجة الكتلة
val result = order.run {
    id = "ORD-002"
    "Processed $id"
}

(3) مقارنة دوال النطاق

الدالة المرجع قيمة الإرجاع حالة الاستخدام
apply this المستقبل إعداد كائن (تسلسل)
run this نتيجة الكتلة تنفيذ + إرجاع نتيجة
with this نتيجة الكتلة استخدام بدون امتداد
let it نتيجة الكتلة تحويلات أمان البطلان
also it المستقبل آثار جانبية (تسجيل / تحقق)

4. البنّاؤون الآمنون الأنواع

(1) بنّاء أساسي

KOTLIN
class OrderBuilder {
    var id: String = ""
    var total: Double = 0.0
    var status: String = "PENDING"
    var customer: String = ""
    private val items = mutableListOf<OrderItem>()

    fun item(block: OrderItemBuilder.() -> Unit) {
        items.add(OrderItemBuilder().apply(block).build())
    }

    fun build() = Order(id, total, status, customer, items.toList())
}

class OrderItemBuilder {
    var sku: String = ""
    var qty: Int = 1
    var unitPrice: Double = 0.0
    fun build() = OrderItem(sku, qty, unitPrice)
}

// نقطة دخول DSL
fun order(block: OrderBuilder.() -> Unit): Order {
    return OrderBuilder().apply(block).build()
}

(2) استخدام بنّاء DSL

KOTLIN
val myOrder = order {
    id = "ORD-001"
    total = 299.99
    customer = "Alice"
    item {
        sku = "SKU-WIDGET"
        qty = 3
        unitPrice = 9.99
    }
    item {
        sku = "SKU-GADGET"
        qty = 1
        unitPrice = 149.99
    }
}

5. @DslMarker لمنع تسريب النطاق

(1) المشكلة: غموض المستقبل الضمني

KOTLIN
order {
    id = "ORD-001"
    item {
        sku = "ABC"
        // خطر: 'id' هنا يمكن أن يشير إلى OrderBuilder.id الخارجي!
        id = "ITEM-001"  // أي id؟ الطلب أم العنصر؟
    }
}

(2) حل @DslMarker

KOTLIN
@DslMarker
annotation class OrderDsl

@OrderDsl
class OrderBuilder {
    var id: String = ""
    fun item(block: OrderItemBuilder.() -> Unit) { ... }
}

@OrderDsl
class OrderItemBuilder {
    var sku: String = ""
    // الآن: لا يمكن الوصول إلى OrderBuilder.id الخارجي من هنا!
}

order {
    id = "ORD-001"  // صحيح: OrderBuilder.id
    item {
        sku = "ABC" // صحيح: OrderItemBuilder.sku
        // id = "X"  // خطأ: لا يمكن الوصول للنطاق الخارجي!
    }
}

(3) مخطط بناء DSL

100%
flowchart TD
    A[كتلة order] --> B[OrderBuilder<br/>id, total, customer]
    B --> C[كتلة item]
    C --> D[OrderItemBuilder<br/>sku, qty, price]
    D --> E[بناء OrderItem]
    E --> F[إضافة لقائمة items]
    B --> G[بناء Order]
    G --> H[إرجاع كائن Order]

6. مقارنة أنماط تصميم DSL

النمط التنفيذ المقروئية أمان الأنواع حالة الاستخدام
بنّاء + مستقبل لامبدا fun order(block: Builder.() -> Unit) ★★★★★ ✅ وقت الترجمة إعدادات متداخلة معقدة
دوال infix infix fun A.to(b: B) ★★★★ ✅ وقت الترجمة تسلسل بسيط
تحميل العوامل الزائد operator fun plus() ★★★ ✅ وقت الترجمة عمليات رياضية / مجموعات
معالجة التعليقات @Annotation class X ★★★ ✅ وقت التوليد تقليل الكود المتكرر
وكيل ديناميكي أسلوب dynamic ★★ ❌ وقت التشغيل إعدادات مرنة / نصوص برمجية

7. مثال Gradle Kotlin DSL

أحد أنجح تطبيقات DSL في كوتلن — نصوص بناء Gradle:

KOTLIN
// build.gradle.kts - هذا IS لغة DSL كوتلن!
plugins {
    kotlin("jvm") version "1.9.22"
    application
}

dependencies {
    implementation(kotlin("stdlib"))
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
    testImplementation(kotlin("test"))
}

kotlin {
    jvmToolchain(17)
}

application {
    mainClass.set("com.order.MainKt")
}

7. مثال كامل: DSL إعدادات طلبات OrderProcessor

KOTLIN
// ============================================
// OrderProcessor - DSL إعدادات الطلبات
// الميزة: بنّاء طلبات آمن الأنواع بـ DSL
// ============================================

@DslMarker
annotation class OrderDsl

data class OrderItem(val sku: String, val qty: Int, val unitPrice: Double) {
    val subtotal: Double get() = qty * unitPrice
}

data class Address(val street: String, val city: String, val country: String)

data class Order(
    val id: String,
    val customer: String,
    val items: List<OrderItem>,
    val shippingAddress: Address?,
    val priority: String,
    val notes: String?
) {
    val total: Double get() = items.sumOf { it.subtotal }
}

@OrderDsl
class OrderBuilder {
    var id: String = ""
    var customer: String = ""
    var priority: String = "STANDARD"
    var notes: String? = null
    private val items = mutableListOf<OrderItem>()
    private var shippingAddress: Address? = null

    fun item(block: OrderItemBuilder.() -> Unit) {
        items.add(OrderItemBuilder().apply(block).build())
    }

    fun items(block: ItemsBuilder.() -> Unit) {
        items.addAll(ItemsBuilder().apply(block).build())
    }

    fun shipTo(block: AddressBuilder.() -> Unit) {
        shippingAddress = AddressBuilder().apply(block).build()
    }

    fun build(): Order {
        require(id.isNotBlank()) { "Order ID is required" }
        require(customer.isNotBlank()) { "Customer is required" }
        return Order(id, customer, items.toList(), shippingAddress, priority, notes)
    }
}

@OrderDsl
class OrderItemBuilder {
    var sku: String = ""
    var qty: Int = 1
    var unitPrice: Double = 0.0

    fun build(): OrderItem {
        require(sku.isNotBlank()) { "SKU is required" }
        return OrderItem(sku, qty, unitPrice)
    }
}

@OrderDsl
class ItemsBuilder {
    private val items = mutableListOf<OrderItem>()
    fun item(block: OrderItemBuilder.() -> Unit) {
        items.add(OrderItemBuilder().apply(block).build())
    }
    fun build() = items.toList()
}

@OrderDsl
class AddressBuilder {
    var street: String = ""
    var city: String = ""
    var country: String = ""
    fun build() = Address(street, city, country)
}

// نقطة دخول DSL
fun order(block: OrderBuilder.() -> Unit): Order =
    OrderBuilder().apply(block).build()

fun main() {
    // DSL آمن الأنواع: يُقرأ كإعدادات، تتحقق منه المترجم
    val myOrder = order {
        id = "ORD-001"
        customer = "Alice"
        priority = "HIGH"

        items {
            item { sku = "SKU-WIDGET"; qty = 3; unitPrice = 9.99 }
            item { sku = "SKU-GADGET"; qty = 1; unitPrice = 149.99 }
            item { sku = "SKU-DOOHICKEY"; qty = 5; unitPrice = 4.50 }
        }

        shipTo {
            street = "123 Main St"
            city = "New York"
            country = "US"
        }

        notes = "Rush delivery requested"
    }

    println("=== Order Summary ===")
    println("ID: ${myOrder.id}")
    println("Customer: ${myOrder.customer}")
    println("Priority: ${myOrder.priority}")
    println("\nItems:")
    myOrder.items.forEach { item ->
        println("  ${item.sku} x${item.qty} @ \$${item.unitPrice} = \$${item.subtotal} USD")
    }
    println("\nTotal: \$${myOrder.total} USD")
    println("Ship to: ${myOrder.shippingAddress}")
    println("Notes: ${myOrder.notes}")

    // تحقق: أمان أنواع وقت الترجمة
    // sku = 123       // خطأ: متوقع String، وليس Int
    // qty = "three"   // خطأ: متوقع Int، وليس String
}

المخرجات:

TEXT 📖 للعرض فقط
=== Order Summary ===
ID: ORD-001
Customer: Alice
Priority: HIGH

Items:
  SKU-WIDGET x3 @ $9.99 = $29.97 USD
  SKU-GADGET x1 @ $149.99 = $149.99 USD
  SKU-DOOHICKEY x5 @ $4.5 = $22.5 USD

Total: $202.46 USD
Ship to: Address(street=123 Main St, city=New York, country=US)
Notes: Rush delivery requested

9. أمثلة عملية سريعة

▶ مثال: DSL بسيط باستخدام lambdas

KOTLIN
// بناء HTML بسيط باستخدام DSL
class Tag(val name: String) {
    private val children = mutableListOf<String>()

    fun content(text: String) {
        children.add(text)
    }

    fun render(): String {
        val inner = children.joinToString("")
        return "<$name>$inner</$name>"
    }
}

class HtmlBuilder {
    private val root = Tag("html")

    fun body(block: Tag.() -> Unit) {
        val body = Tag("body")
        body.block()
        root.content(body.render())
    }

    fun head(block: Tag.() -> Unit) {
        val head = Tag("head")
        head.block()
        root.content(head.render())
    }

    fun render(): String = root.render()
}

// DSL functions
fun html(block: HtmlBuilder.() -> Unit): String {
    val builder = HtmlBuilder()
    builder.block()
    return builder.render()
}

fun Tag.h1(block: Tag.() -> Unit) {
    val h1 = Tag("h1")
    h1.block()
    content(h1.render())
}

fun Tag.p(block: Tag.() -> Unit) {
    val p = Tag("p")
    p.block()
    content(p.render())
}

// الاستخدام
val page = html {
    head {
        content("<title>My Page</title>")
    }
    body {
        h1 {
            content("مرحبا بك في Kotlin DSL")
        }
        p {
            content("هذا مثال على DSL باستخدام lambdas")
        }
    }
}

println(page)

**المخرجات:

TEXT 📖 للعرض فقط
<html><head><title>My Page</title></head><body><h1>مرحبا بك في Kotlin DSL</h1><p>هذا مثال على DSL باستخدام lambdas</p></body></html>

▶ مثال: DSL مع @DslMarker

KOTLIN
// @DslMarker يمنع الوصول العرضي للنطاقات الخارجية
@DslMarker
annotation class HtmlTag

@DslMarker
annotation class BodyTag

// كل نطاق له marker خاص به
@HtmlTag
class SafeHtml {
    private val content = StringBuilder()

    @BodyTag
    fun body(block: Body.() -> Unit) {
        val b = Body()
        b.block()
        content.append(b.render())
    }

    fun render() = "<html>${content}</html>"
}

@BodyTag
class Body {
    private val content = StringBuilder()

    @BodyTag
    fun div(block: Div.() -> Unit) {
        val d = Div()
        d.block()
        content.append(d.render())
    }

    fun text(t: String) { content.append(t) }
    fun render() = "<body>${content}</body>"
}

@BodyTag
class Div {
    private val content = StringBuilder()

    @BodyTag
    fun span(block: Span.() -> Unit) {
        val s = Span()
        s.block()
        content.append(s.render())
    }

    fun text(t: String) { content.append(t) }
    fun render() = "<div>${content}</div>"
}

@BodyTag
class Span {
    private val content = StringBuilder()
    fun text(t: String) { content.append(t) }
    fun render() = "<span>${content}</span>"
}

// دوال DSL
fun html(block: SafeHtml.() -> Unit): String {
    val h = SafeHtml()
    h.block()
    return h.render()
}

@BodyTag
fun Body.div(block: Div.() -> Unit) {}  // نوع مختلف

@BodyTag
fun Div.span(block: Span.() -> Unit) {}

// الاستخدام - مع @DslMarker، لا يمكن الوصول العرضي
val page = html {
    body {
        div {
            span {
                text("نص داخل span")
            }
        }
    }
}
println(page)

// هذا لن يُترجم (محظور بواسطة @DslMarker):
// html {
//     body {
//         span {  // خطأ! span غير متاح في سياق body مباشرة
//             text("...")

**المخرجات:

TEXT 📖 للعرض فقط
<html><body><div><span>نص داخل span</span></div></body></html>

▶ مثال: DSL للاختبار (Should-style)

KOTLIN
// DSL للاختبارات
@DslMarker
annotation class TestDsl

@TestDsl
class TestSuite(val name: String) {
    private val tests = mutableListOf<TestCase>()
    private var currentTest: TestCase? = null

    fun test(description: String, block: TestCase.() -> Unit) {
        val testCase = TestCase(description)
        currentTest = testCase
        testCase.block()
        currentTest = null
        tests.add(testCase)
    }

    @TestDsl
    fun assert(block: Assertions.() -> Unit) {
        Assertions().block()
    }

    fun run(): TestReport {
        val passed = tests.count { it.passed }
        val failed = tests.count { !it.passed }
        return TestReport(name, tests.size, passed, failed)
    }
}

class TestCase(val description: String) {
    var passed: Boolean = false
    var errorMessage: String? = null

    infix fun shouldEqual(expected: Any?) {
        // منطق الاختبار
    }
}

class Assertions {
    infix fun shouldEqual(expected: Any?) {}
    infix fun shouldBe(expected: Any?) {}
    infix fun shouldNotBe(expected: Any?) {}
    fun fail(message: String) {}
}

data class TestReport(val suite: String, val total: Int, val passed: Int, val failed: Int)

// الاستخدام
val suite = TestSuite("Calculator Tests")

suite.test("1 + 1 should equal 2") {
    assert { 1 + 1 shouldEqual 2 }
    passed = true
}

suite.test("2 * 3 should equal 6") {
    assert { 2 * 3 shouldEqual 6 }
    passed = true
}

suite.test("this test should fail") {
    assert { 1 + 1 shouldEqual 3 }  // خاطئ
    passed = false
}

println(suite.run())

**المخرجات:

TEXT 📖 للعرض فقط
TestReport(suite=Calculator Tests, total=3, passed=2, failed=1)

▶ مثال: DSL لتكوين الكائنات

KOTLIN
// DSL لبناء Configuration
class DatabaseConfig {
    var host: String = "localhost"
    var port: Int = 5432
    var database: String = "default"
    var username: String = "admin"
    var password: String = ""
    var poolSize: Int = 10
    var timeout: Long = 30000
    val properties = mutableMapOf<String, String>()

    fun connectString(): String = "jdbc:postgresql://$host:$port/$database"
}

fun database(block: DatabaseConfig.() -> Unit): DatabaseConfig {
    val config = DatabaseConfig()
    config.block()
    return config
}

fun DatabaseConfig.property(key: String, value: String) {
    properties[key] = value
}

// الاستخدام - DSL واضح وقابل للقراءة
val config = database {
    host = "prod-db.example.com"
    port = 5433
    database = "orders"
    username = "app_user"
    password = System.getenv("DB_PASSWORD") ?: ""
    poolSize = 50
    timeout = 60000
    property("sslmode", "require")
    property("ApplicationName", "OrderProcessor")
}

println("Connect string: ${config.connectString()}")
println("Pool size: ${config.poolSize}")
println("Properties: ${config.properties}")

**المخرجات:

TEXT 📖 للعرض فقط
Connect string: jdbc:postgresql://prod-db.example.com:5433/orders
Pool size: 50
Properties: {sslmode=require, ApplicationName=OrderProcessor}

▶ مثال: type-safe builder pattern

KOTLIN
// DSL لطلبات HTTP آمن من حيث الأنواع
sealed class HttpMethod {
    object GET : HttpMethod()
    object POST : HttpMethod()
    object PUT : HttpMethod()
    object DELETE : HttpMethod()
}

class HttpRequest(
    val method: HttpMethod,
    val url: String,
    val headers: Map<String, String> = emptyMap(),
    val body: String? = null
)

class HttpRequestBuilder {
    var method: HttpMethod = HttpMethod.GET
    var url: String = ""
    private val headers = mutableMapOf<String, String>()
    private var bodyContent: String? = null

    fun header(key: String, value: String) {
        headers[key] = value
    }

    fun body(content: String) {
        bodyContent = content
    }

    fun build(): HttpRequest {
        require(url.isNotBlank()) { "URL cannot be blank" }
        return HttpRequest(method, url, headers.toMap(), bodyContent)
    }
}

fun request(block: HttpRequestBuilder.() -> Unit): HttpRequest {
    return HttpRequestBuilder().apply(block).build()
}

// الاستخدام
val req = request {
    method = HttpMethod.POST
    url = "https://api.example.com/orders"
    header("Content-Type", "application/json")
    header("Authorization", "Bearer xxx")
    body("""{"orderId": "ORD-001"}""")
}

println("Request:")
println("  Method: ${req.method::class.simpleName}")
println("  URL: ${req.url}")
println("  Headers: ${req.headers}")
println("  Body: ${req.body}")

**المخرجات:

TEXT 📖 للعرض فقط
Request:
  Method: POST
  URL: https://api.example.com/orders
  Headers: {Content-Type=application/json, Authorization=Bearer xxx}
  Body: {"orderId": "ORD-001"}

▶ مثال: infix function للـ DSL

KOTLIN
// استخدام infix functions لبناء DSL أنيق
class OrderBuilder {
    val items = mutableListOf<OrderItem>()
    var shipping: Shipping = Shipping.STANDARD
    var discount: Double = 0.0
}

class OrderItem(val name: String, val price: Double, var quantity: Int = 1)

enum class Shipping { STANDARD, EXPRESS, OVERNIGHT }

// infix functions
infix fun OrderBuilder.item(item: OrderItem) {
    items.add(item)
}

infix fun OrderBuilder.with(s: Shipping) {
    shipping = s
}

infix fun OrderBuilder.appliedDiscount(percent: Double) {
    discount = percent
}

infix fun OrderBuilder.processedWith(action: () -> Unit) {
    action()
}

// DSL
val order = OrderBuilder().apply {
    item("Laptop" to 1299.99)
    item("Mouse" to 29.99)
    item("Keyboard" to 79.99)
    with Shipping.EXPRESS
    appliedDiscount 10.0  // 10% خصم
}

val subtotal = order.items.sumOf { it.price * it.quantity }
val discountAmount = subtotal * order.discount / 100
val total = subtotal - discountAmount

println("Items: ${order.items.size}")
println("Shipping: ${order.shipping}")
println("Subtotal: \$$subtotal")
println("Discount: \$$discountAmount")
println("Total: \$$total")

**المخرجات:

TEXT 📖 للعرض فقط
Items: 3
Shipping: EXPRESS
Subtotal: $1409.97
Discount: $140.997
Total: $1268.973

▶ مثال: Gradle Kotlin DSL style

KOTLIN
// محاكاة DSL لـ Gradle-style
class Dependencies {
    private val deps = mutableMapOf<String, String>()

    infix fun String.version(v: String) {
        deps[this] = v
    }

    fun implementation(dep: String) {
        println("Implementation: $dep")
    }

    fun testImplementation(dep: String) {
        println("Test implementation: $dep")
    }
}

class Project {
    val dependencies = Dependencies()
    var version: String = "1.0.0"
    var group: String = "com.example"
}

fun project(block: Project.() -> Unit): Project {
    val p = Project()
    p.block()
    return p
}

// الاستخدام - شبيه بـ build.gradle.kts
val myProject = project {
    group = "com.example"
    version = "1.0.0"

    dependencies {
        "kotlinx-coroutines-core" version "1.7.3"
        "kotlinx-serialization-json" version "1.6.0"
        implementation("org.slf4j:slf4j-api:2.0.9")
        testImplementation("org.junit.jupiter:junit-jupiter:5.10.1")
    }
}

println("\nProject: ${myProject.group}:${myProject.version}")

**المخرجات:

TEXT 📖 للعرض فقط
Implementation: org.slf4j:slf4j-api:2.0.9
Test implementation: org.junit.jupiter:junit-jupiter:5.10.1

Project: com.example:1.0.0

❓ أسئلة شائعة

س ما الفرق بين DSL وواجهة برمجة تطبيقات عادية؟
ج DSL يهدف إلى "أن يُقرأ كلغة طبيعية أو إعدادات"، محقق عبر مستقبلات لامبدا + دوال امتداد + استدعاءات infix. واجهات البرمجة العادية تعطي الأولوية للوظيفة على المقروئية.
س هل @DslMarker إلزامي؟
ج غير إلزامي، لكن موصى به بشدة. بدونه، يمكن لنطاقات DSL المتداخلة الوصول عرضياً لأعضاء من النطاقات الخارجية، مما يؤدي لأخطاء. @DslMarker يمنع هذا وقت الترجمة.
س ما الفرق بين مستقبلات لامبدا ومعاملات لامبدا؟
ج المستقبلات تُنصل عبر this (ضمني)؛ المعاملات عبر it (صريح). المستقبلات تناسب DSL (this الضمني يبدو أكثر طبيعية)؛ المعاملات تناسب الاستدعاءات (it الصريح أوضح).
س ما أداء DSL؟
ج DSL تنشئ كائنات Builder، التي تتحمل حمل تخصيص طفيف. لكن في سيناريوهات الإعدادات (ليست مسارات ساخنة)، هذا مهمل. تجنب استخدام DSL في حلقات داخلية بملايين الاستدعاءات في الثانية.
س ما الفرق بين DSL كوتلن و DSL Groovy؟
ج DSL كوتلن يمتلك فحص أنواع وقت الترجمة وإكمال IDE التلقائي ودعم إعادة الهيكلة. DSL Groovy مرن ديناميكياً لكنه يفتقد فحوصات وقت الترجمة. Gradle Kotlin DSL يستبدل تدريجياً Groovy DSL.
س كيف أضيف منطقاً شرطياً لـ DSL؟
ج DSL هي نفسها كود كوتلن — يمكنك استخدام if/when/for وغيرها من تدفق التحكم داخل الكتل. هذه ميزة كبيرة على ملفات الإعدادات — إعدادات + منطق في واحد.

📖 ملخص


📝 تمارين

  1. مبتدئ (⭐): استخدم apply لإعداد كائن Order، تعيين id و total و status. تلميح: order.apply { id = "ORD-001"; total = 299.99 }
  2. متوسط (⭐⭐): ابنِ DSL لـ EmailBuilder: email { from("a@b.com"); to("c@d.com"); subject("Hi") }. تلميح: fun email(block: EmailBuilder.() -> Unit) + مستقبل لامبدا
  3. متقدم (⭐⭐⭐): استخدم @DslMarker لتنفيذ DSL متداخل: order { customer { name("Alice") }; item { sku("ABC") } }، مع ضمان عدم وصول النطاقات الداخلية لأعضاء خارجية. تلميح: @DslMarker + بنّاء متعدد الطبقات

← السابق | التالي →

Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%