الفرق بين المراجعتين لصفحة: «Kotlin/multi declarations»
طلا ملخص تعديل |
ط تعديل مصطلح متحول |
||
سطر 1: | سطر 1: | ||
<noinclude>{{DISPLAYTITLE:التصريحات بالتفكيك (Destructuring Declarations) في لغة Kotlin}}</noinclude> | <noinclude>{{DISPLAYTITLE:التصريحات بالتفكيك (Destructuring Declarations) في لغة Kotlin}}</noinclude> | ||
== التصريح بالتفكيك == | == التصريح بالتفكيك == | ||
قد تحتاج في بعض الأحيان لتفكيك الكائن (object) إلى عددٍ من | قد تحتاج في بعض الأحيان لتفكيك الكائن (object) إلى عددٍ من المتغيِّرات، مثل:<syntaxhighlight lang="kotlin"> | ||
val (name, age) = person | val (name, age) = person | ||
</syntaxhighlight>تٌسمَّى الصيغة السابقة بالتصريح بالتفكيك والذي يُنشِئ أكثر من | </syntaxhighlight>تٌسمَّى الصيغة السابقة بالتصريح بالتفكيك والذي يُنشِئ أكثر من متغيِّر بنفس الوقت (وهما المتغيِّران<code>name</code> و <code>age</code>) حيث يُسمح باستخدامهما بشكلٍ مستقلٍ تمامًا كما في الشيفرة الآتية:<syntaxhighlight lang="kotlin"> | ||
println(name) | println(name) | ||
println(age) | println(age) | ||
سطر 13: | سطر 13: | ||
كما ويُستفاد من التصريح بالتفكيك في حلقة <code>for</code> بالشكل:<syntaxhighlight lang="kotlin"> | كما ويُستفاد من التصريح بالتفكيك في حلقة <code>for</code> بالشكل:<syntaxhighlight lang="kotlin"> | ||
for ((a, b) in collection) { ... } | for ((a, b) in collection) { ... } | ||
</syntaxhighlight>حيث تحصل | </syntaxhighlight>حيث تحصل المتغيِّرات<code>a</code> و <code>b</code> على القيم من استدعاء الدالتين <code>component1()</code> و <code>component2()</code> في عناصر المجموعة (collection). | ||
== تطبيقٌ عمليٌّ: إعادة قيمتين من الدالة == | == تطبيقٌ عمليٌّ: إعادة قيمتين من الدالة == | ||
سطر 44: | سطر 44: | ||
</syntaxhighlight>مما يجعل من السهل استخدام التصريحات بالتفكيك في حلقات <code>for</code> بالاعتماد على maps (وكذلك كائنات مجموعات أصناف البيانات [collections of data class instances] وما يماثلها). | </syntaxhighlight>مما يجعل من السهل استخدام التصريحات بالتفكيك في حلقات <code>for</code> بالاعتماد على maps (وكذلك كائنات مجموعات أصناف البيانات [collections of data class instances] وما يماثلها). | ||
== استخدام الشرطة السفليّة (_) | == استخدام الشرطة السفليّة (_) للمتغيرات غير المُستخدَمة (بدءًا من الإصدار 1.1) == | ||
إن لم يكن هناك حاجةٌ | إن لم يكن هناك حاجةٌ للمتغيِّر في التصريح بالتفكيك فيمكن الاستغناءُ عن اسمه بالشرطة السفليّة مثل:<syntaxhighlight lang="kotlin"> | ||
val (_, status) = getResult() | val (_, status) = getResult() | ||
</syntaxhighlight>وبهذه الطريقة لن تُستدعَى دالة الجزء (component function) الموافقةِ له. | </syntaxhighlight>وبهذه الطريقة لن تُستدعَى دالة الجزء (component function) الموافقةِ له. | ||
== التفكيك في lambdas (بدءًا من الإصدار 1.1) == | == التفكيك في lambdas (بدءًا من الإصدار 1.1) == | ||
تُستخدَم صيغةُ التصريحات بالتفكيك في | تُستخدَم صيغةُ التصريحات بالتفكيك في معاملات lambda أيضًا، وإذا كان معامل lambda من النوع <code>Pair</code> (أو من النوع <code>Map.Entry</code> أو أي نوعٍ آخر يحتوي على دالة جزءٍ [component function] مناسبةٍ) فيُمكن حينئذٍ استخدام أكثر من معامل (تُحاط المعاملات بالأقواس <code>()</code>)، كما في الشيفرة الآتية:<syntaxhighlight lang="kotlin"> | ||
map.mapValues { entry -> "${entry.value}!" } | map.mapValues { entry -> "${entry.value}!" } | ||
map.mapValues { (key, value) -> "$value!" } | map.mapValues { (key, value) -> "$value!" } | ||
</syntaxhighlight>ويتَّضِح الفرق بين التصريح عن | </syntaxhighlight>ويتَّضِح الفرق بين التصريح عن معاملين والتصريح عنهما بالتفكيك، كما يلي:<syntaxhighlight lang="kotlin"> | ||
{ a -> ... } // | { a -> ... } // معامل واحد | ||
{ a, b -> ... } // | { a, b -> ... } // معاملان | ||
{ (a, b) -> ... } // تصريح مفكك | { (a, b) -> ... } // تصريح مفكك بمتغيرين | ||
{ (a, b), c -> ... } // تصريح مفكك | { (a, b), c -> ... } // تصريح مفكك بمتغيرين ومعامل ثالث مستقل | ||
</syntaxhighlight>فإن كان أحد أجزاء التصريح بالتفكيك غير مستخدمٍ يُستعاض عنه بالشرطة السفليّة دون الحاجة لتسميته، مثل:<syntaxhighlight lang="kotlin"> | </syntaxhighlight>فإن كان أحد أجزاء التصريح بالتفكيك غير مستخدمٍ يُستعاض عنه بالشرطة السفليّة دون الحاجة لتسميته، مثل:<syntaxhighlight lang="kotlin"> | ||
map.mapValues { (_, value) -> "$value!" } | map.mapValues { (_, value) -> "$value!" } | ||
</syntaxhighlight>كما ويمكن تحديد النوع الإجماليّ | </syntaxhighlight>كما ويمكن تحديد النوع الإجماليّ لمعاملات التصريح بالتفكيك أو لمعاملٍ واحدٍ منها بشكلٍ منفصلٍ كما في الشيفرة الآتية:<syntaxhighlight lang="kotlin"> | ||
map.mapValues { (_, value): Map.Entry<Int, String> -> "$value!" } | map.mapValues { (_, value): Map.Entry<Int, String> -> "$value!" } | ||
مراجعة 17:10، 4 يوليو 2018
التصريح بالتفكيك
قد تحتاج في بعض الأحيان لتفكيك الكائن (object) إلى عددٍ من المتغيِّرات، مثل:
val (name, age) = person
تٌسمَّى الصيغة السابقة بالتصريح بالتفكيك والذي يُنشِئ أكثر من متغيِّر بنفس الوقت (وهما المتغيِّرانname
و age
) حيث يُسمح باستخدامهما بشكلٍ مستقلٍ تمامًا كما في الشيفرة الآتية:
println(name)
println(age)
إذ يُترجَم التصريح بالتفكيك كما يلي:
val name = person.component1()
val age = person.component2()
حيث تُعدُّ الدالتان component1()
و component2()
مثالًا عن الاصطلاحات الأساسيّة المُستخدَمة في لغة Kotlin (راجع المُعامِلات مثل +
و *
وحلقات for
و... إلخ.)، ويُسمَح بوجود أيّ كائنٍ في الجانب الأيمن من التصريح بالتفكيك طالما أمكن استدعاء العدد المطلوب من دوال الأجزاء (component functions) عبره (قد تكون بالأسماء component3()
و component4()
وهكذا) والتي يجب أن تُحدَّد بالكلمة المفتاحيّة operator
للسماح باستخدامها في هذا التصريح.
كما ويُستفاد من التصريح بالتفكيك في حلقة for
بالشكل:
for ((a, b) in collection) { ... }
حيث تحصل المتغيِّراتa
و b
على القيم من استدعاء الدالتين component1()
و component2()
في عناصر المجموعة (collection).
تطبيقٌ عمليٌّ: إعادة قيمتين من الدالة
عند الحاجة إلى إعادة عنصرين من الدالة (لنقل مثلًا إعادة كائن النتيجة وحالةٍ ما) فإن الطريقة المُتَّفق عليها للقيام بذلك هي إنشاء صنفٍ للبيانات (data class) وإعادة كائنٍ منه، كما في الشيفرة الآتية:
data class Result(val result: Int, val status: Status)
fun function(...): Result {
// بعض الحسابات
return Result(result, status)
}
// الآن.. استخدام الدالة
val (result, status) = function(...)
ويُسمَح باستخدام التصريح بالتفكيك هنا لأنّ أصناف البيانات تعرِّف دوال الأجزاء componentN()
تلقائيًا.
ملاحظة: يمكن استخدام الصنف القياسي Pair
لتعيد الدالة function()
النوع Pair<Int, Status>
، ولكن من الأفضل تسميةُ البيانات بما يتناسب مع استخدامها.
تطبيقٌ عمليٌّ: التصريحات بالتفكيك و Maps
إنّ الطريقة الأنسب للمرور بعناصر map هي كما في الشيفرة الآتية:
for ((key, value) in map) {
// القيام بالتعليمات استنادًا إلى القيمة والمفتاح
}
وهنا يجب التقيد بما يلي:
- تمثيل كائن map كتسلسلٍ (sequence) من القيم من خلال الدالة
iterator()
- تمثيل كلٍّ من العناصر كزوجٍ (pair) من خلال الدالتين
component1()
وcomponent2()
إذ تزوِّد المكتبة القياسية بمثل هذه الإضافات:
operator fun <K, V> Map<K, V>.iterator(): Iterator<Map.Entry<K, V>> = entrySet().iterator()
operator fun <K, V> Map.Entry<K, V>.component1() = getKey()
operator fun <K, V> Map.Entry<K, V>.component2() = getValue()
مما يجعل من السهل استخدام التصريحات بالتفكيك في حلقات for
بالاعتماد على maps (وكذلك كائنات مجموعات أصناف البيانات [collections of data class instances] وما يماثلها).
استخدام الشرطة السفليّة (_) للمتغيرات غير المُستخدَمة (بدءًا من الإصدار 1.1)
إن لم يكن هناك حاجةٌ للمتغيِّر في التصريح بالتفكيك فيمكن الاستغناءُ عن اسمه بالشرطة السفليّة مثل:
val (_, status) = getResult()
وبهذه الطريقة لن تُستدعَى دالة الجزء (component function) الموافقةِ له.
التفكيك في lambdas (بدءًا من الإصدار 1.1)
تُستخدَم صيغةُ التصريحات بالتفكيك في معاملات lambda أيضًا، وإذا كان معامل lambda من النوع Pair
(أو من النوع Map.Entry
أو أي نوعٍ آخر يحتوي على دالة جزءٍ [component function] مناسبةٍ) فيُمكن حينئذٍ استخدام أكثر من معامل (تُحاط المعاملات بالأقواس ()
)، كما في الشيفرة الآتية:
map.mapValues { entry -> "${entry.value}!" }
map.mapValues { (key, value) -> "$value!" }
ويتَّضِح الفرق بين التصريح عن معاملين والتصريح عنهما بالتفكيك، كما يلي:
{ a -> ... } // معامل واحد
{ a, b -> ... } // معاملان
{ (a, b) -> ... } // تصريح مفكك بمتغيرين
{ (a, b), c -> ... } // تصريح مفكك بمتغيرين ومعامل ثالث مستقل
فإن كان أحد أجزاء التصريح بالتفكيك غير مستخدمٍ يُستعاض عنه بالشرطة السفليّة دون الحاجة لتسميته، مثل:
map.mapValues { (_, value) -> "$value!" }
كما ويمكن تحديد النوع الإجماليّ لمعاملات التصريح بالتفكيك أو لمعاملٍ واحدٍ منها بشكلٍ منفصلٍ كما في الشيفرة الآتية:
map.mapValues { (_, value): Map.Entry<Int, String> -> "$value!" }
map.mapValues { (_, value: String) -> "$value!" }