في بيرل ، هل هناك طريقة رشيقة لتحويل undef إلى 0 يدويًا؟
سؤال
لدي جزء في هذا النموذج:
my $a = $some_href->{$code}{'A'}; # a number or undef
my $b = $some_href->{$code}{'B'}; # a number or undef
$a = 0 unless defined($a);
$b = 0 unless defined($b);
my $total = $a + $b;
الواقع هو أكثر فوضى ، لأن أكثر من متغيرين قلقون.
ما أريد حقًا أن أكتبه هو:
my $total = $some_href->{$code}{'A'} + $some_href->{$code}{'B'};
وقد قمت بتقييم UNDEF بشكل صحيح على 0 لكنني أحصل على هذه التحذيرات في كل عملية تشغيل تقريبًا:
Use of uninitialized value in addition (+) at Stats.pm line 192.
ما هي أفضل طريقة لجعل هذه الرسائل تختفي؟
NB: أنا "استخدم صارمة" و "استخدم التحذيرات" إذا كان ذلك ذا صلة.
المحلول
من الجيد أنك تستخدم strict
و warnings
. الغرض من التحذيرات هو تنبيهك عندما يرى بيرل السلوك الذي من المحتمل أن يكون غير مقصود (وبالتالي غير صحيح). عندما تفعل ذلك عن عمد ، من الجيد تمامًا تعطيل التحذير محليًا. undef
يعامل باسم 0
في السياقات الرقمية. إذا كنت على ما يرام مع وجود قيم غير محددة وجعلها تقييم الصفر ، فما عليك سوى تعطيل التحذير:
my $total;
{
no warnings 'uninitialized';
$total = $some_href->{$code}{A} + $some_href->{$code}{B};
}
ملاحظة: تعطيل فقط التحذيرات التي تحتاجها ، والقيام بذلك في نطاق أصغر ممكن.
إذا كنت تعجب من تعطيل التحذيرات ، فهناك خيارات أخرى. اعتبارا من بيرل 5.10 يمكنك استخدام //
(محدد أو) عامل تشغيل القيم الافتراضية. قبل أن يستخدم الناس في كثير من الأحيان ||
(منطقي أو) ، ولكن يمكن أن يفعل الشيء الخطأ للقيم التي تقيم الخاطئة. تتمثل الطريقة القوية في القيم الافتراضية في إصدارات PRE-5.10 من Perl إلى التحقق مما إذا كانت defined
.
$x = $y // 42; # 5.10+
$x = $y || 42; # < 5.10 (fragile)
$x = defined $y ? $y : 42; # < 5.10 (robust)
نصائح أخرى
يمكنك إيقاف تشغيل التحذير "غير المعدل" لثانية:
my $a;
my $b = 1;
{
no warnings 'uninitialized';
my $c = $a+$b; # no warning
}
my $c = $a+$b; # warning
أو يمكنك دائرة قصيرة إلى الصفر:
my $d = ($a||0)+$b; # no warning
لا تبدو لطيفة جدا بالنسبة لي رغم ذلك.
أثناء إضافتها ، ما عليك سوى تصفية undefs.
use List::Util 'sum';
my $total = sum (0, grep {defined} $some_href->{$code}{'A'}, $some_href->{$code}{'B'});
او حتى
use List::Util 'sum';
my $total = sum (0, grep {defined} map {$some_href->{$code}{$_}} 'A', 'B');
my $a = $some_href->{$code}{'A'} || 0;
my $b = $some_href->{$code}{'B'} || 0;
my $total = $a + $b;
في هذه الحالة ، لا بأس في التعامل مع القيم الخاطئة مثل القيم غير المحددة بسبب قيمة الاحتياطية.