نسخ القوائم في Kotlin: النسخ العميق مقابل النسخ السطحي

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

استنساخ القوائم في Kotlin: كيف لا تقع في مشاكل المراجع؟

\n\n

تخيل: أنت تكتب تطبيقًا بلغة Kotlin، وتعالج قائمة من البيانات، وفجأة تتغير المصفوفة الأصلية من تلقاء نفسها. ألم مألوف؟ على الأرجح، لقد نسخت المرجع فقط، وليس القائمة نفسها. في هذه المقالة، سنستعرض جميع الطرق القانونية لاستنساخ قائمة في Kotlin — من النسخ السطحي إلى النسخ العميق. بدون حشو، فقط الكود والشروحات.

\n\n

الموضوع مستوحى من سؤال شائع على Stack Overflow (أكثر من 200,000 مشاهدة): "How to clone or copy a list in kotlin". دعنا ننهي الأمر مرة واحدة وإلى الأبد ونفهم كيف نسخ قائمة Kotlin بشكل صحيح، حتى لا نفقد البيانات ولا نصاب بالجنون.

\n\n

لماذا لا يعمل الإسناد البسيط؟

\n\n

في Kotlin، كما في Java، القوائم هي أنواع مرجعية. إذا كتبت:

\n\n
val original = mutableListOf("A", "B", "C")\nval copy = original  // هذه ليست نسخة!\ncopy.add("D")\nprintln(original) // [A, B, C, D] — تغيرت الأصلية!
\n\n

لقد أنشأت ببساطة مرجعًا ثانيًا لنفس الكائن في الذاكرة. أي تغيير عبر copy سينعكس على original. لتجنب ذلك، تحتاج إلى استخدام طرق خاصة لنسخ القائمة في Kotlin.

\n\n

أفضل 5 طرق لنسخ قائمة في Kotlin

\n\n

سنستعرض جميع الخيارات الرئيسية: من toList() البسيط إلى النسخ العميق اليدوي. اختر ما يناسب مهمتك.

\n\n

1. toList() — الطريقة الأبسط

\n\n

الطريقة toList() تنشئ نسخة جديدة غير قابلة للتغيير من القائمة. هذا نسخ سطحي (shallow copy) — العناصر نفسها لا تتكرر، لكن هيكل القائمة يصبح مستقلاً.

\n\n
val original = listOf("Kotlin", "Java", "Python")\nval copy = original.toList()\n\n// copy هو كائن جديد\nprintln(copy === original) // false — مراجع مختلفة\nprintln(copy == original)  // true — محتوى متطابق
\n\n

مثالي للقوائم البسيطة من السلاسل النصية أو الأرقام. إذا كنت بحاجة إلى نسخة قابلة للتغيير — استخدم toMutableList().

\n\n

2. toMutableList() — للنسخ القابلة للتغيير

\n\n

هل تريد نسخة يمكنك تعديلها؟ toMutableList() هو خيارك. ينشئ MutableList جديد بنفس العناصر.

\n\n
val original = listOf(1, 2, 3)\nval mutableCopy = original.toMutableList()\nmutableCopy.add(4)\n\nprintln(original)       // [1, 2, 3]\nprintln(mutableCopy)    // [1, 2, 3, 4] — الأصل لم يتأثر
\n\n

هذه هي الطريقة الأكثر شيوعًا لاستنساخ mutable list في Kotlin.

\n\n

3. ArrayList(collection) — كلاسيكية Java

\n\n

إذا كنت قادمًا من Java، ستجد هذه الطريقة مألوفة. المُنشئ ArrayList يأخذ مجموعة أخرى وينسخ عناصرها.

\n\n
val original = listOf("A", "B", "C")\nval arrayCopy = ArrayList(original)\narrayCopy[0] = "Z"\n\nprintln(original)    // [A, B, C]\nprintln(arrayCopy)   // [Z, B, C]
\n\n

يعمل بسرعة ويمكن التنبؤ به. لكن تذكر: هذا أيضًا shallow copy.

\n\n

4. map() — مع تحويل العناصر

\n\n

إذا كنت لا تريد فقط نسخ القائمة، بل أيضًا تحويل العناصر، استخدم map(). ينشئ قائمة جديدة بناءً على القديمة، بتطبيق دالة لامدا على كل عنصر.

\n\n
val numbers = listOf(10, 20, 30)\nval doubled = numbers.map { it * 2 }\n\nprintln(numbers)  // [10, 20, 30]\nprintln(doubled)  // [20, 40, 60]
\n\n

للنسخ البسيط بدون تغييرات، يمكنك كتابة numbers.map { it }، لكن هذا زائد عن الحاجة — من الأفضل استخدام toList().

\n\n

5. النسخ العميق (deep copy) للكائنات المعقدة

\n\n

جميع الطرق السابقة تقوم بالنسخ السطحي. إذا كانت قائمتك تحتوي على كائنات قابلة للتغيير (مثل data class مع حقول)، فإن تغيير كائن في النسخة سيؤثر على الأصل:

المدونات

توصيات الكتب