Destructuring declaration — قابلیتی در Kotlin است که یک شی را به چند متغیر در یک عبارت تجزیه میکند. ساختار val (name, age) = user همزمان دو متغیر را اعلام میکند و مقادیر را از اجزای شی به آنها اختصاص میدهد. طبق مستندات Kotlin (2026)، تجزیه ساختاری حجم کد را هنگام کار با data class تا 30–50٪ کاهش میدهد. Destructuring declaration کد را مختصرتر و خواناتر میکند.
نکات کلیدی
Destructuring declaration (اعلام تجزیهکننده) — یک ساختار نحوی در Kotlin است که به شما امکان میدهد یک نمونه از کلاس را در یک عبارت به چند متغیر تجزیه کنید. سمت چپ شامل لیست متغیرها در پرانتز و سمت راست شیء قابل تجزیه است. Kotlin به طور خودکار برای هر متغیر تابع componentN() مناسب را فراخوانی میکند، جایی که N شماره ترتیبی متغیر در پرانتز است.
Destructuring declaration اغلب با data class استفاده میشود. کامپایلر Kotlin به طور خودکار برای data class توابع component1(), component2() و غیره را بر اساس تعداد ویژگیها در سازنده اولیه ایجاد میکند. برای کلاسهای معمولی بدون اصلاحکننده data، componentN() ایجاد نمیشود، اما میتوان آنها را به صورت دستی به عنوان توابع عملگر با کلمه کلیدی operator تعریف کرد.
Destructuring declaration به دلیل توانایی خود در سادهسازی کد هنگام کار با مجموعههای جفتی، نتایج توابع و پیمایش Map به یک الگوی محبوب تبدیل شده است. به جای نوشتن person.firstName, person.lastName، توسعهدهنده مینویسد val (firstName, lastName) = person. این کار تعداد خطوط را کاهش میدهد و خوانایی را افزایش میدهد، به ویژه در حلقهها و لامبداها.
هنگام مواجهه با ساختار val (a, b) = obj، کامپایلر Kotlin کد زیر را تولید میکند: val a = obj.component1(); val b = obj.component2(). اگر متغیرها با var اعلام شده باشند، انتسابهای var تولید میشوند. نوع هر متغیر از نوع بازگشتی تابع componentN() مربوطه استنباط میشود. این بدان معنی است که destructuring declaration کاملاً نوع-ایمن است و در مرحله کامپایل بررسی میشود.
data class Person(val firstName: String, val lastName: String, val age: Int)
fun main() {
val person = Person("Alice", "Smith", 30)
// Destructuring: component1(), component2(), component3()
val (firstName, lastName, age) = person
println("$firstName $lastName, $age سال")
}
در لیستینگ، Person یک data class با سه ویژگی است. Kotlin component1() → firstName، component2() → lastName، component3() → age را تولید میکند. عبارت val (firstName, lastName, age) = person این توابع را فراخوانی کرده و نتایج را اختصاص میدهد. مهم: نام متغیرها ممکن است با نام ویژگیها مطابقت نداشته باشد — کامپایلر فقط به ترتیب componentN() و انواع آنها نگاه میکند. میتوان فقط N ویژگی اول را تجزیه کرد و بقیه را نادیده گرفت.
Data class — کاندید اصلی برای destructuring declaration است. هر data class به طور خودکار برای همه ویژگیهای سازنده اولیه componentN() دریافت میکند. ترتیب componentN() با ترتیب اعلام ویژگیها مطابقت دارد. این بدان معنی است که با تغییر ترتیب فیلدها در data class، ترتیب متغیرها در تجزیه تغییر میکند — که میتواند منجر به باگهای نامرئی شود.
// تجزیه Pair
val pair = Pair("key", 42)
val (key, value) = pair
println("$key -> $value")
// تجزیه Triple
val triple = Triple("A", "B", "C")
val (first, second, third) = triple
// Map.Entry در حلقه
val map = mapOf("a" to 1, "b" to 2)
for ((k, v) in map) {
println("$k = $v")
}
Pair و Triple — کلاسهای استاندارد با تجزیه ساختاری آماده برای دو و سه جزء. Pair اغلب به عنوان نوع بازگشتی توابعی استفاده میشود که باید دو مقدار مرتبط را بدون ایجاد یک data class جداگانه برگردانند. در حلقه for روی Map.Entry، ساختار (k, v) = entry کلید و مقدار را از طریق component1() و component2() تجزیه میکند. این یک الگوی استاندارد برای پیمایش Map در Kotlin است که کاملاً جایگزین فراخوانیهای صریح key و value میشود.
اگر در تجزیه ساختاری برخی اجزا مورد نیاز نباشند، Kotlin اجازه میدهد آنها را با زیرخط _ جایگزین کنید. این کار خوانایی را بهبود میبخشد — خواننده بلافاصله میبیند که آن جزء نادیده گرفته شده است. علاوه بر این، استفاده از _ از دسترسی تصادفی به متغیر مقداردهینشده جلوگیری میکند: کامپایلر هیچ متغیری برای _ ایجاد نمیکند، که هشدارهای مربوط به متغیرهای استفادهنشده را حذف میکند.
data class Order(
val id: Long,
val customerName: String,
val amount: Double,
val status: String
)
fun process(orders: List<Order>) {
for ((id, _, amount) in orders) {
println("سفارش $id: $amount")
}
}
در لیستینگ، Order چهار ویژگی دارد، اما در حلقه فقط id و amount مورد نیاز است. زیرخط به جای customerName به کامپایلر میگوید «component2() را نادیده بگیر». Kotlin component2() را فراخوانی نمیکند و برای این جزء متغیری ایجاد نمیکند. مهم: زیرخط فقط در destructuring declaration قابل استفاده است، نه در سازنده data class. اگر چندین جزء متوالی نادیده گرفته شوند، هر کدام زیرخط مخصوص خود را دارند.
برای کلاسهای بدون اصلاحکننده data میتوان به صورت دستی componentN() را با اضافه کردن کلمه کلیدی operator تعریف کرد. این امکان استفاده از destructuring declaration را با هر کلاسی، از جمله کلاسهای شخص ثالث که کد منبع آنها قابل تغییر نیست، فراهم میکند — کافی است یک تابع extension با operator بنویسید. این رویکرد به ویژه برای کلاسهای کتابخانهای و کلاسهای کد Java که componentN() خودکار ندارند مفید است.
class Rect(val width: Int, val height: Int)
operator fun Rect.component1(): Int = width
operator fun Rect.component2(): Int = height
// برای کلاس Java با getterها
operator fun Dimension.component1(): Int = width
operator fun Dimension.component2(): Int = height
fun main() {
val rect = Rect(1920, 1080)
val (w, h) = rect
println("رزولوشن: ${w}x${h}")
}
در مثال، Rect یک کلاس معمولی بدون data است. توابع extension با operator fun component1() = width و component2() = height پشتیبانی از تجزیه ساختاری را اضافه میکنند. به طور مشابه برای java.awt.Dimension: operator extension روی Dimension امکان تجزیه آن به width و height را فراهم میکند. محدودیت: حداکثر تعداد اجزا برای destructuring declaration — 5. در تئوری میتوان component6() و بالاتر را تعریف کرد، اما Kotlin نحو مناسبی برای 6+ متغیر در پرانتز ایجاد نخواهد کرد.
سوالات متداول
بله، هر data class به طور خودکار برای همه ویژگیهای سازنده اولیه componentN() دریافت میکند. ویژگیهای اعلامشده در بدنه کلاس (از طریق سازنده بدون val/var) componentN() تولید نمیکنند.
اگر در val (a, b, c) = obj شیء فقط دو تابع component داشته باشد، کامپایلر خطا میدهد. اگر متغیرها کمتر باشند (val (a) = pair)، Kotlin فقط component1() را فراخوانی کرده و component2() را نادیده میگیرد — خطایی رخ نمیدهد.
بله، Map.Entry از تجزیه ساختاری پشتیبانی میکند: val (key, value) = map.entries.first(). برای کل Map به طور همزمان تجزیه ساختاری کار نمیکند — فقط عنصر به عنصر، در حلقه for یا از طریق iterator.
بله، Kotlin از تجزیه ساختاری در پارامترهای لامبدا پشتیبانی میکند: map.forEach { (k, v) -> ... }. برای data class در پارامترهای لامبدا باید پرانتزهای تو در تو در اطراف پارامتر اضافه کرد.
Kotlin تا 5 متغیر در destructuring declaration پشتیبانی میکند. اگر نیاز به تجزیه بیش از پنج ویژگی دارید، آنها را در data classهای تو در تو ترکیب کنید یا از Pair/Triple در داخل یک متغیر استفاده کنید.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید