ما هي أفضل الممارسات في روبي لتجنب إساءة استخدام المهمة "="؟
-
12-11-2019 - |
سؤال
لقد تعرضت للعض عدة مرات بسبب نسيان ذلك x = y
في روبي يجعل x يشير إلى نفس الكائن مثل y؛أنا معتاد على اللغات التي تعني، بمصطلحات روبي، x = y.dup
.عندما أنسى هذا، أتغير عن غير قصد y
عندما أعتقد أنه آمن على الجانب الأيمن من المهمة.
أستطيع أن أرى أنه سيكون من المنطقي تجنب البساطة x = y
المهام دون سبب خاص، ولكن نفس الشيء يمكن أن يكون كامنًا في أماكن أخرى مثل
name = (person.last_name.blank? ? 'unknown' : person.last_name)
حيث في وقت لاحق name << title
في الواقع سيتم تغيير person.last_name وليس الاسم فقط.
إذا حدث لك هذا أيضًا، فكيف تعلمت تجنبه؟هل هناك علامات أو أنماط حمراء معينة يجب البحث عنها؟هل تنظر بعين الشك إلى كل مهمة تقوم بها؟هل تستعمل .dup
كثيراً؟لا أعرف ما إذا كان استخدام روبي سيصبح أمرًا طبيعيًا بالنسبة لي، لذا فإن أي نصائح مفيدة ستكون موضع ترحيب.
المحلول
قد يبدو هذا غير تقليدي في لغة (حتمية بشكل أساسي) مثل روبي، لكن نصيحتي هي:يتجنب الأضرار الجانبية من خلال عدم تحديث الكائنات على الإطلاق (إلا عند الضرورة القصوى)؛إنشاء أخرى جديدة بدلا من ذلك.أنت تدفع القليل من الأداء ولكنك ستحصل على تعليمات برمجية أكثر وضوحًا وأكثر إحكاما وأكثر نمطية وأسهل في التصحيح.
http://en.wikipedia.org/wiki/Functional_programming
لذلك، في المثال الخاص بك، ما عليك سوى إنشاء سلسلة جديدة باسم جديد:
complete_name = name + title
نصائح أخرى
مجرد إضافة إلى إجابة tokland:
يصر النهج الوظيفي على ثبات - أي.عدم تغيير الكائنات الموجودة، ولكن إنشاء كائن آخر عندما تريد تغيير الكائن الأصلي.وهذا يتعارض إلى حد ما مع النموذج الموجه للكائنات الذي تقدمه روبي أيضًا (تحتفظ الكائنات بحالتها داخليًا، والتي يمكن تغييرها عن طريق استدعاء الأساليب عليها)، لذلك عليك تحقيق التوازن قليلاً بين النهجين (من ناحية أخرى، نحن نستفيد من خلال وجود نماذج متعددة يمكن الوصول إليها بسهولة في لغة واحدة).
لذا، هناك ثلاثة أشياء يجب تذكرها الآن:
- تعرف على المهمة في روبي:لا شيء سوى تسمية كائن.لذلك، عندما تقول
y=x
, ، أنت تقول فقط "نعطي اسمًا آخرy
إلى ما سميت بهx
". name << title
يتحول كائن يسمىname
.name += title
يأخذ الكائنات المسماةname
وtitle
, ، يسلسلهم في آخر كائن، ويعين اسم الكائن الجديدname
.لا يتحول أي شيء.
لقد واجهت أيضًا مثل هذا الموقف وأدى إلى حدوث خطأ، واستغرق الأمر نصف يوم لاكتشافه.لقد فعلت شيئًا كهذا بشكل أساسي
hash = {....}
filename = object.file_name
hash.each |k, v| {file_name.gsub!(k, v) if file_name.include? k}
كان هذا الرمز داخل حلقة وفي الحلقة توقعت المتغير file_name
ليتم ضبطها مرة أخرى على القيمة الأصلية.ولكن تم تغيير object.file_name أثناء أدائي file_name.gsub!
.هناك طريقتان لحل هذه المشكلة.إما استبدال .gsub!
الاتصال مع file_name = file_name.gsub
أو افعل file_name = object.file_name.dup
.اخترت الخيار الثاني.
أعتقد أننا يجب أن نكون حذرين مع الأساليب !
و <<
, حيث يقومون بتغيير الكائن الأصلي الذي يتصرفون عليه، خاصة بعد مهام كهذه.
يجب ألا تقوم الطريقة بتعديل متغير (على سبيل المثال.باستخدام عامل التحول) ما لم ينص تعريفه على أنه سيتم تعديله.
لذا:لا تقم مطلقًا بتعديل كائن بطريقة لم تقم (أ) بإنشائه أو (ب) بتوثيق تعديله.