لماذا يقوم Perl بتقييم الكود في $ {...} أثناء الاستيفاء السلسلة؟
-
22-09-2019 - |
سؤال
لماذا يعمل المقتطف التالي على الإطلاق؟ وما هو الشر الممكن باستخدام هذا؟ ولكن على محمل الجد ، هل هناك أي سبب ، الرمز في ${}
يتم تقييمها على الإطلاق ثم تستخدم كمرجع العددية؟
use strict;
no strict 'refs';
our $message = "Hello world!";
print "${ lc 'MESSAGE' }\n";
المحلول
حسنا، ما لم تستخدم المراجع الرمزية. افترض الرمز التالي:
my %messages = (hello => "Hello world!", bye => "Bye-bye, world!");
sub get_message_ref { return \$messages{$_[0]} }; # returns scalarref
print "${ get_message_ref('bye') }\n";
أوافق على ذلك ، فائدتها ليست واضحة مع scalarrefs ، لكنها مفيدة للغاية مع ArrayRefs.
print "keys: @{[keys %messages]}\n";
نصائح أخرى
نوضح هذا بعمق في بيرل وسيطة.
بناء الجملة العام للبحث المتغير هو:
SIGIL BLOCK INDEXY-THING
للحصول على عدد بسيط يشبه:
print $ { foo };
ربما تكون قد رأيت هذا عندما تحتاج إلى فصل اسم متغير عن الأشياء المحيطة به:
print "abc${foo}def\n";
إذا كان لديك فقط معرف Perl في الكتلة ولا توجد فوضى محيطة ، فيمكنك ترك الأقواس ، وهي الحالة الشائعة:
print $foo;
ومع ذلك ، هذا هو نفس الشيء لإلغاء مرجع:
SIGIL BLOCK-RETURNING-REFERENCE INDEXY-THINGS
إذا كان الشيء الذي تحصل عليه في الكتلة مرجعًا ، فإن بيرل يحاول أن يضعفه كما طلبته أيضًا:
my $ref = \ '12345';
print $ { $ref };
هذه كتلة حقيقية ، وليس فقط السكر. يمكنك الحصول على العديد من العبارات التي تريدها هناك:
print $ { my $ref = \ '1234'; $ref };
أنت الآن لا تحدد فقط معرف Perl ، لذلك لا تفترض Perl أنك تعطيه معرفًا ويقوم بتنفيذ التعليمات البرمجية ويستخدم النتيجة كمرجع. النظر في الفرق بين هذه متطابقة تقريبا say
صياغات:
use 5.010;
our $foo = "I'm the scalar";
sub foo { \ "I'm the sub" }
say ${foo};
say ${foo;};
في تلك الثانية say
يرى بيرل شبه الكولون ، ويدرك أنه ليس معرفًا ، ويفسر الرمز داخل الأقواس كنص ، ويعيد النتيجة. نظرًا لأن النتيجة مرجعية ، فإنها تستخدم ${...}
لترشيح ذلك. لا يهم من أين تفعل ذلك ، بحيث تقوم بذلك داخل سلسلة مزدوجة غير مخصصة.
أيضا ، لاحظ our
هناك. هذا مهم الآن بعد أن فكرت في شيء أكثر صعوبة:
use 5.010;
our $foo = "I'm the scalar";
sub foo { \ "I'm the sub" }
sub baz { 'foo' }
say ${foo};
say ${foo;};
say ${baz;};
intreprets perl التي تدوم say
كرمز ويرى أن النتيجة ليست مرجعا ؛ إنها السلسلة البسيطة foo
. يرى بيرل أنه ليس مرجعًا ولكنه الآن في سياق dereferencing لذا فهو يقوم مرجعًا رمزيًا (مثل يصف جريج بيكون). نظرًا لأن المراجع الرمزية تعمل مع المتغيرات في جدول الرموز ، فإن ذلك $foo
يجب أن يكون متغير الحزمة.
نظرًا لأنه من السهل إفساد هذا الأمر ، strict
لديه فحص مفيد لذلك. ومع ذلك ، عند إيقاف تشغيله ، لا تتفاجأ عندما تعضك. قون
من "استخدام المراجع" قسم من وثائق Perlref:
في أي مكان تضع معرفًا (أو سلسلة من المعرفات) كجزء من اسم متغير أو روتين فرعي ، يمكنك استبدال المعرف بكتلة إرجاع مرجع للنوع الصحيح. بمعنى آخر ، يمكن كتابة الأمثلة السابقة مثل هذا:
$bar = ${$scalarref}; push(@{$arrayref}, $filename); ${$arrayref}[0] = "January"; ${$hashref}{"KEY"} = "VALUE"; &{$coderef}(1,2,3); $globref->print("output\n"); # iff IO::Handle is loaded
من المسلم به ، أنه من السخف بعض الشيء استخدام التجعيد في هذه الحالة ، ولكن يمكن أن تحتوي الكتلة على أي تعبير تعسفي ، على وجه الخصوص ، التعبيرات المشتركة:
&{ $dispatch{$index} }(1,2,3); # call correct routine
بسبب القدرة على حذف التجعيد للحالة البسيطة
$$x
, ، غالبًا ما يخطئ الناس في مشاهدة رموز إزالة التخلص من المشغلين المناسبة ، ويتساءلون عن أسباقهم. إذا كانوا ، على الرغم من ذلك ، يمكنك استخدام الأقواس بدلاً من الأقواس. هذا ليس هو الحال. النظر في الفرق أدناه ؛ الحالة 0 هي نسخة قصيرة من الحالة 1 ، وليس الحالة 2:$$hashref{"KEY"} = "VALUE"; # CASE 0 ${$hashref}{"KEY"} = "VALUE"; # CASE 1 ${$hashref{"KEY"}} = "VALUE"; # CASE 2 ${$hashref->{"KEY"}} = "VALUE"; # CASE 3
الحالة 2 خادعة أيضًا في أنك تصل إلى متغير يسمى
%hashref
, ، وليس التخلص من خلال$hashref
إلى التجزئة ، من المفترض أنه يشير. ستكون هذه الحالة 3.
في وقت لاحق في "المراجع الرمزية":
قلنا أن الإشارات الربيع إلى الوجود عند الضرورة إذا كانت غير محددة ، لكننا لم نقول ما يحدث إذا تم تعريف القيمة المستخدمة كمرجع بالفعل ، ولكنها ليست مرجعًا صعبًا. إذا كنت تستخدمه كمرجع ، فسيتم معاملته كمرجع رمزي. وهذا يعني أن قيمة العددية هي اسم المتغير ، بدلاً من رابط مباشر لقيمة مجهولة (ربما).