راهنمای ایجاد DSL در کاتلین — به زبان ساده

۱۱۲ بازدید
آخرین به‌روزرسانی: ۰۱ مهر ۱۴۰۲
زمان مطالعه: ۲ دقیقه
راهنمای ایجاد DSL در کاتلین — به زبان ساده

یکی از قابلیت‌های واقعاً مفید کاتلین امکان ساخت DSL سفارشی است. در این مقاله به بررسی روش ایجاد DSL در کاتلین می‌پردازیم. به این منظور تنها به چهار چیز نیاز دارید:

  • نمادگذاری میانوندی
  • متدهای اکستنشن
  • لامبدا
  • لامبدا با گیرنده

در ادامه این موارد را یک به یک بررسی می‌کنیم.

نمادگذاری میانوندی

در «نمادگذاری میانوندی» (Infix Notation) براکت‌ها و نقطه‌ها را حذف می‌کنیم:

1class Car {
2   fun drive(miles: Int) {
3      ...
4   }
5}
6val car = Car()
7car.drive(10) // normal stuff

کافی است نمادگذاری میانوندی را پیش از اعلان متد اضافه کنیم تا کار کند:

1class Car {
2   infix fun drive(miles: Int) {
3      ...
4   }
5}
6val car = Car()
7car drive 10 // no brackets! no dots!

متدهای اکستنشن

با استفاده از متدهای اکستنشن می‌توان تابع‌های جدید را به هر کلاس بدون نیاز به ارث‌بری اضافه کرد.

1val name = "Ahmed Riz"
2name.shout() // won't compile as shout() is not part of String class

برای این که آن را بدون ارث‌بری به عنوان بخشی از کلاس String دربیاوریم، باید متد shout را بدون پیشوند String ایجاد کنیم.

1fun String.shout() {
2   println("$this !") // this refers to the value of string itself
3}
4val name = "Ahmed Riz"
5name.shout()  // works! and prints out: Ahmed Riz !

متدهای اکستنشن دامنه پروژه‌ای دارند. می‌توان از هر جایی درون پروژه به آن‌ها دسترسی داشت.

لامبدا

با استفاده از لامبداها می‌توان «الفاظ تابعی» (function literals) را به تابع‌های مرتبه بالاتر ارسال کرد.

1// a higher order function
2fun process(value: Int, operation: (Int) -> Unit) {
3    operation(value)
4}
5// when calling, we can pass in a lambda expression
6process(10, { value -> println(value) })
7// and because it's the last param, we can extract it out
8// just to clean things up even further 
9process(10) { value -> println(value) }

لامبدا با گیرنده

با استفاده از لامبدا به همراه گیرنده می‌توان الفاظ تابعی را به تابع‌های مرتبه بالاتر اما با نوع گیرنده ارسال کرد.

1// slight change to the previous higher order function
2// now instead of operation: (Int) -> Unit
3// we'll do operation: Int.() -> Unit
4// This makes Int the receiver type
5fun process(value: Int, operation: Int.() -> Unit) {
6    value.operation()
7}
8// usage now becomes
9process(10) { println(this) } // prints out: 10

ترکیب همه موارد

در این بخش با روش ساخت یک DSL خاص که صرفاً به منظور نمایش شیوه کار ایجاد می‌شود آشنا می‌شویم.

1val myProfile = "Ahmed Rizwan" profile {
2    age = 90
3    phone = "123 456 789"      
4}

کد تبدیل آن به یک DSL معتبر به سادگی زیر است:

1class Profile(
2    val name: String,
3    var age: Int? = null,
4    var phone: String? = null
5)
6
7infix fun String.profile(create: Profile.() -> Unit): Profile {
8    val profile = Profile(this)
9    profile.create()
10    return profile
11}

سخن پایانی

بدین ترتیب موفق شدیم یک DSL سفارشی در کاتلین ایجاد کنیم. با این که این DSL ممکن است در دنیای واقعی چندان مفید نباشد، اما امیدواریم به این ترتیب ایده خوبی از شیوه استفاده از این قابلیت‌های متفاوت کاتلین برای ساخت DSL سفارشی برای خودتان به دست آورده باشید.

اگر این مطلب برای شما مفید بوده است‌، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۴ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
android.jlelse
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *