سؤال

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

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

المحلول

إنه سلوك طبيعي للغة.نقلا عن perlsyn الصفحة الرئيسية:

الرقم 0, ، الخيوط '0' و "", ، القائمة الفارغة (), ، و undefكلها خاطئة في سياق منطقي.جميع القيم الأخرى صحيحة.نفي القيمة الحقيقية ! أو not إرجاع قيمة خاطئة خاصة.عند تقييمها كسلسلة يتم التعامل معها على أنها "", ، ولكن كرقم ، يتم التعامل معها على أنها 0.

ولهذا السبب، يجب أن يكون هناك طريقة للعودة 0 من استدعاء النظام الذي يتوقع العودة 0 كقيمة إرجاع (ناجحة)، واترك طريقة للإشارة إلى حالة الفشل من خلال إرجاع قيمة خاطئة فعليًا. "0 but true" يخدم هذا الغرض.

نصائح أخرى

لأنه مشفر في قلب لغة Perl للتعامل معه كرقم.يعد هذا اختراقًا لإنشاء اتفاقيات Perl و ioctlتلعب اتفاقيات 's معًا;من perldoc -f ioctl:

قيمة الإرجاع ioctlfcntl) على النحو التالي:

if OS returns:      then Perl returns:

    -1              undefined value
     0              string "0 but true"
anything else       that number

وبالتالي فإن Perl يعيد صحيحًا على النجاح والخطأ في الفشل ، ومع ذلك لا يزال بإمكانك تحديد القيمة الفعلية التي يتم إرجاعها بسهولة بواسطة نظام التشغيل:

$retval = ioctl(...) || -1;
printf "System returned %d\n", $retval;

السلسلة الخاصة "0 but true" معفى من -w شكاوى حول التحويلات الرقمية غير السليمة.

بالإضافة إلى ما قاله الآخرون، "0 but true" تعتبر حالة خاصة لأنها لا تحذر في سياق رقمي:

$ perl -wle 'print "0 but true" + 3'
3
$ perl -wle 'print "0 but crazy" + 3'
Argument "0 but crazy" isn't numeric in addition (+) at -e line 1.
3

القيمة 0 but true هي حالة خاصة في بيرل.على الرغم من أنه بالنسبة لعينيك الفانية، فإنه لا يبدو كرقم، ويدرك بيرل الحكيم والمعرفي أنه رقم حقًا.

يتعلق الأمر بحقيقة أنه عندما يُرجع روتين فرعي لـ Perl قيمة 0، فمن المفترض أن الروتين فشل أو أرجع قيمة خاطئة.

تخيل أن لدي روتينًا فرعيًا يُرجع مجموع رقمين:

die "You can only add two numbers\n" if (not add(3, -2));
die "You can only add two numbers\n" if (not add("cow", "dog"));
die "You can only add two numbers\n" if (not add(3, -3));

لن تموت العبارة الأولى لأن الروتين الفرعي سيعود أ 1.هذا جيد.سوف تموت العبارة الثانية لأن الروتين الفرعي لن يتمكن من الإضافة بقرة ل كلب.

والبيان الثالث؟

هممم، يمكنني أن أضيف 3 ل -3.أنا فقط أحصل على 0, ، ولكن بعد ذلك سوف يموت برنامجي على الرغم من أن add عملت روتين فرعي!

للالتفاف على هذا، يرى بيرل 0 but true ليكون رقما.إذا كان لي يضيف إرجاع روتين فرعي ليس فقط 0, ، لكن 0 لكن صحيح, ، بياني الثالث سيعمل.

لكن هو 0 لكن صحيح صفر رقمي؟جرب هذا:

my $value = "0 but true";
print qq(Add 1,000,000 to it: ) . (1_000_000 + $value) . "\n";
print "Multiply it by 1,000,000: " . 1_000_000 * $value . "\n";

نعم، إنه صفر!

ال فِهرِس الروتين الفرعي هو جزء قديم جدًا من لغة Perl وكان موجودًا قبل مفهوم 0 لكن صحيح كان حولها.من المفترض إرجاع موضع السلسلة الفرعية الموجودة في السلسلة:

index("barfoo", "foo");   #This returns 3
index("barfoo", "bar");   #This returns 0
index("barfoo", "fu");    #This returns ...uh...

البيان الأخير يعود أ -1.مما يعني أنني لو فعلت هذا:

if ($position = index($string, $substring)) {
   print "It worked!\n";
}
else {
   print "If failed!\n";
}

كما أفعل عادة مع الوظائف القياسية، فإنه لن يعمل.إذا استخدمت "barfoo" و"bar" كما فعلت في العبارة الثانية، فإن else سيتم تنفيذ البند، ولكن إذا استخدمت "barfoo" و"fu" كما في الجملة الثالثة، فإن if سيتم تنفيذ الشرط.ليس ما أريد.

ومع ذلك، إذا index عاد الروتين الفرعي 0 لكن صحيح للبيان الثاني و undef بالنسبة للبيان الثالث، يا if/else كان من الممكن أن ينجح الشرط.

قد ترى أيضًا السلسلة "0E0" المستخدم في كود بيرل, ، وهو يعني نفس الشيء، حيث 0E0 يعني فقط 0 مكتوبًا بالتدوين الأسي.ومع ذلك، نظرًا لأن Perl يعتبر "0" أو "" أو undef خطأً فقط، فإنه يتم تقييمه على أنه صحيح في سياق منطقي.

تم ترميزه بشكل ثابت في الكود المصدري لـ Perl، وتحديدًا في Perl_grok_number_flags في numeric.c.

عند قراءة هذا الرمز، اكتشفت أن السلسلة "infinity" (غير حساسة لحالة الأحرف) تجتاز اختبار look_like_number أيضًا.لم أكن أعرف ذلك.

في سياق عدد صحيح، يتم تقييمه إلى 0 (الجزء الرقمي في بداية السلسلة) وهو صفر.في السياق العددي، إنها قيمة غير فارغة، لذا فهي صحيحة.

  • if (int("0 but true")) { print "zero"; }

    (لا يوجد إخراج)

  • if ("0 but true") { print "true"; }

    (المطبوعات صحيحة)

0 تعني خطأ في لغة Perl (واللغات الأخرى المرتبطة بـ C).بالنسبة للجزء الأكبر، هذا سلوك معقول.علاج اللغات الأخرى (لوا على سبيل المثال). 0 على أنه صحيح وقدم رمزًا مميزًا آخر (غالبًا لا شيء أو خطأ شنيع) لتمثيل قيمة غير حقيقية.

إحدى الحالات التي لا تعمل فيها طريقة Perl بشكل جيد هي عندما تريد إرجاع رقم أو قيمة خاطئة في حالة فشل الوظيفة لسبب ما.على سبيل المثال، إذا كتبت دالة تقرأ سطرًا من ملف وترجع عدد الأحرف الموجودة في السطر.قد يكون الاستخدام الشائع للوظيفة شيئًا مثل:

while($c = characters_in_line($file)){
    ...
};

لاحظ أنه إذا كان عدد الأحرف في سطر معين هو 0، فإن بينما ستنتهي الحلقة قبل نهاية الملف.لذلك Characters_in_line يجب أن تكون الوظيفة حالة خاصة 0 حرفًا وتعود '0 لكن صحيح' بدلاً من.بهذه الطريقة ستعمل الوظيفة على النحو المنشود في ملف بينما حلقة، ولكن أيضًا تُرجع الإجابة الصحيحة في حالة استخدامها كرقم.

لاحظ أن هذا ليس جزءًا مدمجًا من اللغة.بل إنه يستفيد من قدرة Perl على تفسير السلسلة كرقم.لذلك يتم أحيانًا استخدام لسعات أخرى بدلاً من ذلك. دي بي آي الاستخدامات "0E0", ، على سبيل المثال.عند تقييمها في سياق رقمي، فإنها تعود 0, ، ولكن في سياق منطقي، خطأ شنيع.

الأشياء الباطلة:

  • "".
  • "0".
  • الأشياء التي تشدد على تلك.

"0 but true" ليست واحدة من تلك، لذلك فهي ليست كاذبة.

علاوة على ذلك، يعود بيرل "0 but true" حيث يُتوقع وجود رقم للإشارة إلى نجاح الدالة على الرغم من أنها أعادت الصفر. syseek مثال على هذه الوظيفة.وبما أنه من المتوقع أن يتم استخدام القيمة كرقم، يتم ترميز لغة Perl لاعتبارها رقمًا.ونتيجة لذلك، لا يتم إصدار أي تحذيرات عند استخدامه كرقم، و looks_like_number("0 but true") يعود صحيحا.

يمكن العثور على "أصفار حقيقية" أخرى على http://www.perlmonks.org/?node_id=464548.

مثال آخر على "0 ولكن صحيح":

تستخدم وحدة DBI "0E0" كقيمة إرجاع لاستعلامات التحديث أو الحذف التي لا تؤثر على أي سجلات.يتم تقييمه إلى صحيح في سياق منطقي (يشير إلى أنه تم تنفيذ الاستعلام بشكل صحيح) وإلى 0 في سياق رقمي يشير إلى أنه لم يتم تغيير أي سجلات بواسطة الاستعلام.

لقد وجدت للتو دليلاً على أن السلسلة "0 ولكن صحيح" مدمجة فعليًا في المترجم، كما أجاب بعض الأشخاص هنا بالفعل:

$ strings /usr/lib/perl5/5.10.0/linux/CORE/libperl.so | grep -i true
Perl_sv_true
%-p did not return a true value
0 but true
0 but true

عندما تريد كتابة دالة تُرجع إما قيمة عددية أو خطأ شنيع أو undef (أي.لحالة الخطأ) فعليك الانتباه إلى القيمة صفر.إن إرجاعها خطأ ويجب ألا يشير إلى حالة الخطأ، لذا فإن إرجاع "0 لكن صحيح" يجعل قيمة إرجاع الدالة صحيحة بينما يستمر في تمرير القيمة صفر عند إجراء العمليات الحسابية عليها.

"0 ولكن صحيح" هي سلسلة مثل أي سلسلة أخرى ولكن بسبب بناء جملة بيرل يمكن أن تخدم غرضًا مفيدًا، وهو إرجاع عدد صحيح صفر من دالة دون أن تكون النتيجة "خطأ" (في نظر بيرل).

ولا يلزم أن تكون السلسلة "0 ولكنها صحيحة"."0 ولكن خطأ" لا يزال "صحيحًا" بالمعنى المنطقي.

يعتبر:

if(x)

for x:        yields:
1             -> true
0             -> false
-1            -> true
"true"        -> true
"false"       -> true
"0 but true"  -> true
int("0 but true") ->false

والنتيجة من كل هذا هو أنه يمكنك الحصول على:

sub find_x()

ويكون هذا الكود قادرًا على طباعة "0" كإخراج له:

if($x = find_x)
{
   print int($x) . "\n";
}

لا تزال السلسلة ``0 ولكن صحيح'' حالة خاصة:

for arg in "'0 but true'" "1.0*('0 but true')" \
           "1.0*('0 but false')" 0 1 "''" "0.0" \
           "'false'" "'Ja'" "'Nein'" "'Oui'" \
           "'Non'" "'Yes'" "'No'" ;do
    printf "%-32s: %s\n" "$arg" "$(
        perl -we '
            my $ans=eval $ARGV[0];
            $ans=~s/^(Non?|Nein)$//;
            if ($ans) {
                printf "true:  |%s|\n",$ans
            } else {
                printf "false: |%s|", $ans
          };' "$arg"
        )"
    done

إعطاء ما يلي:(لاحظ "التحذير"!)

'0 but true'                    : true:  |0 but true|
1.0*('0 but true')              : false: |0|
Argument "0 but false" isn't numeric in multiplication (*) at (eval 1) line 1.
1.0*('0 but false')             : false: |0|
0                               : false: |0|
1                               : true:  |1|
''                              : false: ||
0.0                             : false: |0|
'false'                         : true:  |false|
'Ja'                            : true:  |Ja|
'Nein'                          : false: ||
'Oui'                           : true:  |Oui|
'Non'                           : false: ||
'Yes'                           : true:  |Yes|
'No'                            : false: ||

...ولا تنس RTFM!

man -P'less +"/0 but [a-z]*"' perlfunc

       ... "fcntl".  Like "ioctl", it maps a 0 return from the system call
           into "0 but true" in Perl.  This string is true in boolean
           context and 0 in numeric context.  It is also exempt from the
           normal -w warnings on improper numeric conversions. ...
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top