لماذا تستخدم البرمجة بيرل المحلية (وليس بلدي) لـ FileHandles؟

StackOverflow https://stackoverflow.com/questions/613906

  •  03-07-2019
  •  | 
  •  

سؤال

عندما أقرأ من خلال برمجة بيرل, ، الطبعة الثانية ، صفحة 51 ، شيء يربكني:

sub newopen {
    my $path = shift;
    local *FH;    #not my!
    open (FH, $path) || return undef;
    return *FH;
}

$fh = newopen('/etc/passwd');

أنا أعلم ، لماذا لا يوصينا باستخدام بلدي؟ حتى الآن ، لا يمكنني رؤية أي شيء سوف يحدث خطأ إذا استخدمنا ().

شكرًا!

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

المحلول

الإجابة المبتذلة هي أنه يجب عليك استخدامها local لان my *FH هو خطأ بناء الجملة.

الجواب "اليمين" (ولكن ليس المنير للغاية) هو أنك تفعل ذلك خطأ. يجب أن تستخدم FileHandles المعجمية والشكل ثلاثي الأداء من open في حين أن.

sub newopen {
    my $path = shift;
    my $fh;
    open($fh, '<', $path) or do {
        warn "Can't read file '$path' [$!]\n";
        return;
    }
    return $fh;
}

للإجابة حقا لماذا يتطلب شرحًا للفرق بين المتغيرات المعجمية والعالمية وبين نطاق المتغير ومدته.

نطاق المتغير هو جزء البرنامج حيث يكون اسمه صالحًا. النطاق هو خاصية ثابتة. مدة المتغير ، من ناحية أخرى ، هي خاصية ديناميكية. المدة هي الوقت أثناء تنفيذ البرنامج الذي يوجد فيه المتغير ويحمل قيمة.

my يعلن عن متغير معجمي. المتغيرات المعجمية لها نطاق من نقطة الإعلان إلى نهاية الكتلة المرفقة (أو الملف). يمكنك الحصول على متغيرات أخرى مع نفس الاسم في نطاقات مختلفة دون صراع. (يمكنك أيضًا إعادة استخدام اسم في نطاقات متداخلة ، لكن لا تفعل ذلك.) يتم إدارة مدة المتغيرات المعجمية المرجعية. طالما أن هناك إشارة واحدة على الأقل إلى متغير ، فإن القيمة موجودة ، حتى لو لم يكن الاسم صالحًا في نطاق معين! my كما أن له تأثير وقت التشغيل - يخصص الجديد متغير مع الاسم المحدد.

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

العودة إلى المثال: *FH هو متغير عالمي. بشكل أكثر دقة هو "typeglob" - حاوية لمجموعة من المتغيرات العالمية. يحتوي typeglob على فتحة لكل نوع من أنواع المتغيرات الأساسية (العددية ، الصفيف ، التجزئة) بالإضافة إلى بعض الأشياء الأخرى. تاريخيا ، استخدم Perl typeglobs لتخزين FileHandles و local-ساعدهم في ضمان أنهم لم يتجولوا في بعضهم البعض. المتغيرات المعجمية لا تحتوي على typeglobs وهذا هو السبب في القول my *FH هو خطأ بناء الجملة.

في الإصدارات الحديثة من المتغيرات المعجمية Perl وينبغي استخدامها كملف FileHandles بدلاً من ذلك. وهذا يعيدنا إلى الجواب "الصحيح".

نصائح أخرى

في رمز العينة الخاص بك ، المكالمة إلى الروتين الفرعي المضمن open يستخدم كلمة عارية كمقبض الملف ، وهو ما يعادل متغير عالمي. كما إجابة ناثان فيمان أوضح ، باستخدام local سيتم توطين هذه الكلمة العارية إلى كتلة الكود الحالية ، في حالة تعريف متغير عالمي آخر مع نفس الاسم في مكان آخر في البرنامج النصي أو الوحدة النمطية. سيمنع هذا المتغير العالمي المحدد مسبقًا من القضاء على الإعلان الجديد.

كانت هذه ممارسة شائعة جدًا في أيام البيرل القديمة ، ولكن اعتبارًا من Perl 5.6 ، من الأفضل استخدام العددية (مع my الإعلان الذي ألمحت إليه في سؤالك) لتحديد مقبض الملف الخاص بك بالإضافة إلى ذلك ، استخدم دعوة الوسيطة الثلاثة إلى open.

use Carp;
open my $error_log, '>>', 'error.log' or croak "Can't open error.log: $OS_ERROR";

جانبا ، يرجى ملاحظة أنه بالنسبة لقراءة الإدخال/الإخراج القياسية ، لا يزال من الأفضل استخدام الوسيطة open:

use Carp;
open my $stdin, '<-' or croak "Can't open stdin: $OS_ERROR";

بدلاً من ذلك ، يمكنك استخدام IO::File الوحدة النمطية تبارك مقبض الملف إلى الفصل:

use IO::File;
my $error_log = IO::File->new('error.log', '>>') or croak "Can't open error.log: $OS_ERROR");

غالبية الائتمان هنا يذهب إلى داميان كونواي ، مؤلف كتاب "أفضل الممارسات" الكتب الممتازة. إذا كنت جادًا في تطوير Perl ، فأنت مدين لنفسك بشراء هذا الكتاب.

لماذا تقرأ كتابًا قديمًا. الطبعة الثالثة كانت خارج لفترة طويلة! ما هو إصدار Perl الذي تستخدمه؟ يصف الطبعة الثانية بيرل 5.004 (5.4.x) أو ما شابه.

في هذه الأيام ، يجب ألا تستخدم تدوين TypeGlob لمقابض الملف ؛ استخدم "مقابض الملف المعجمية" (انظر افتح, ، أعتقد) أو FileHandle الوحدة ، أو أحد أقاربها بدلاً من ذلك.


بفضل مايكل شويرن و YSTH للتعليقات المدمجة هنا.

أعتقد أن ذلك بسبب my يخصص نسخة جديدة من المتغير على المكدس ، وفقدت عند الخروج من الكتلة. local يحفظ القائمة *FH في مكان آخر ويتجاوز الموجود *FH. يعيد القديم عند الخروج من المكدس. مع my ال *FH يخرج TypeGlob من النطاق عند الخروج من الكتلة. مع local إنه يحافظ على وجوده ، حتى تتمكن من الاستمرار في استخدامه بعد إعادته.

لست متأكدًا بنسبة 100 ٪ من هذا ، لكن ربما يمكن أن يوجهك في الاتجاه الصحيح.

انظر FileHandles الموضعية هنا, ، انا اعتقد هذا يفسر الامر.

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