سؤال

في جاوة عندما تفعل

int b = 0;
b = b + 1.0;

تحصل على خسارة محتملة لخطأ الدقة. ولكن لماذا إذا قمت بذلك

int b = 0;
b += 1.0;

لا يوجد أي خطأ؟

هل كانت مفيدة؟

المحلول

هذا بسبب b += 1.0; يعادل b = (int) ((b) + (1.0));. ال تضييق التحويل البدائي (JLS 5.1.3) مخفي في عملية المهمة المركب.

JLS 15.26.2 مشغلي الواجبات المركبة (JLS Third Edition):

تعبير تخصيص مركب للنموذج E1 OP = E2 يعادل E1 = (T) ((E1) OP (E2)), ، أين ر هو نوع E1, ، ماعادا هذا E1 يتم تقييمه مرة واحدة فقط.

على سبيل المثال ، الكود التالي صحيح:

short x = 3;
x += 4.6;

ونتائج في x وجود القيمة 7 لأنه يعادل:

short x = 3;
x = (short)(x + 4.6);

وهذا ما يفسر أيضًا سبب تجميع الكود التالي:

byte b = 1;
int x = 5;
b += x; // compiles fine!

لكن هذا لا:

byte b = 1;
int x = 5;
b = b + x; // DOESN'T COMPILE!

تحتاج إلى الإلقاء بشكل صريح في هذه الحالة:

byte b = 1;
int x = 5;
b = (byte) (b + x); // now it compiles fine!

تجدر الإشارة إلى أن المصبوب الضمني في المهام المركبة هو موضوع اللغز 9: Tweedledum من الكتاب الرائع Java Puzzlers. إليك بعض المقتطفات من الكتاب (تم تحريره قليلاً للإيجاز):

يعتقد العديد من المبرمجين ذلك x += i; هو مجرد اختصار ل x = x + i;. هذا ليس صحيحًا تمامًا: إذا كان نوع النتيجة أوسع من المتغير ، فإن مشغل المهمة المركب يؤدي تحويلًا بدائيًا صامتًا.

لتجنب المفاجآت غير السارة ، لا تستخدم عوامل التعيينات المركب على متغيرات النوع byte, short, ، أو char. عند استخدام مشغلي التعيين المركب على متغيرات النوع int, ، تأكد من أن التعبير على الجانب الأيمن ليس من النوع long, float, ، أو double. عند استخدام مشغلي التعيين المركب على متغيرات النوع float, ، تأكد من أن التعبير على الجانب الأيمن ليس من النوع double. هذه القواعد كافية لمنع المترجم من توليد قوالب ضيقة خطيرة.

بالنسبة لمصممي اللغة ، من المحتمل أن يكون من الخطأ لمشغلي المهام المركبة إنشاء قوالب غير مرئية ؛ يجب أن تكون المهام المركبة حيث يكون للمتغير نوع أضيق من نتيجة الحساب غير قانونية.

الفقرة الأخيرة تجدر الإشارة إلى: C# أكثر صرامة في هذا الصدد (انظر C# مواصفات اللغة 7.13.2 تعيين المركب).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top