هل مشغل Perl Flip-Flop قد تم التنصت عليه؟ لديها دولة عالمية ، كيف يمكنني إعادة تعيينها؟

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

سؤال

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

هل يمكنني إعادة ضبطه (ربما ستكون هذه إضافة جيدة إلى Perl 4-esque بالكاد تستخدم reset()))؟ أو ، ألا توجد طريقة لاستخدام هذا المشغل بأمان؟

كما أنني لا أرى هذا (بتات السياق العالمية) موثقة في أي مكان في perldoc perlop هل هذا خطأ؟

شفرة

use feature ':5.10';
use strict;
use warnings;

sub search {
    my $arr = shift;
    grep { !( /start/ .. /never_exist/ ) } @$arr;
}

my @foo = qw/foo bar start baz end quz quz/;
my @bar = qw/foo bar start baz end quz quz/;

say 'first shot - foo';
say for search \@foo;

say 'second shot - bar';
say for search \@bar;

المفسد

$ perl test.pl
first shot
foo
bar
second shot
هل كانت مفيدة؟

المحلول

هل يمكن لشخص أن يوضح ما هي المشكلة في الوثائق؟ يشير بوضوح إلى:

Each ".." operator maintains its own boolean state.

هناك بعض الغموض حول معنى "كل" ، لكنني لا أعتقد أن الوثائق ستخدم جيدًا من خلال تفسير معقد.

لاحظ أن التكرار الآخرين في بيرل (each أو سياق القياسي glob) يمكن أن تؤدي إلى نفس المشاكل. لأن الدولة ل each مرتبط بتجزئة معينة ، وليس جزءًا معينًا من التعليمات البرمجية ،each يمكن إعادة تعيينها عن طريق الاتصال (حتى في سياق الفراغ) keys على التجزئة. لكن ل glob أو .., ، لا توجد آلية إعادة تعيين متاحة إلا عن طريق استدعاء التكرار حتى يتم إعادة تعيينها. عينة من خلل الكرة الأرضية:

sub globme {
    print "globbing $_[0]:\n";
    print "got: ".glob("{$_[0]}")."\n" for 1..2;
}
globme("a,b,c");
globme("d,e,f");
__END__
globbing a,b,c:
got: a
got: b
globbing d,e,f:
got: c
Use of uninitialized value in concatenation (.) or string at - line 3.
got: 

بالنسبة للفضول المفرط ، إليك بعض الأمثلة التي يكون فيها نفس .. في المصدر أ مختلف .. المشغل أو العامل:

إغلاق منفصل:

sub make_closure {
    my $x;
    return sub {
        $x if 0;  # Look, ma, I'm a closure
        scalar( $^O..!$^O ); # handy values of true..false that don't trigger ..'s implicit comparison to $.
    }
}
print make_closure()->(), make_closure()->();
__END__
11

التعليق على $x if 0 خط لترى أن غير المسلسلات لها واحدة .. العملية التي تشاركها جميع "النسخ" ، مع وجود الإخراج 12.

الخيوط:

use threads;
sub coderef { sub { scalar( $^O..!$^O ) } }
coderef()->();
print threads->create( coderef() )->join(), threads->create( coderef() )->join();
__END__
22

يبدأ الرمز الخيوط بكل ما كانت عليه .. كان قبل إنشاء الخيط ، لكن التغييرات في حالتها في الخيط معزولة عن التأثير على أي شيء آخر.

العودية:

sub flopme {
    my $recurse = $_[0];
    flopme($recurse-1) if $recurse;
    print " "x$recurse, scalar( $^O..!$^O ), "\n";
    flopme($recurse-1) if $recurse;
}
flopme(2)
__END__
1
 1
2
  1
3
 2
4

كل عمق من العودية منفصل .. مشغل.

نصائح أخرى

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

sub make_search {
    my( $left, $right ) = @_;
    sub {
        grep { !( /\Q$left\E/ .. /\Q$right\E/ ) } @{$_[0]};
        }
}

my $search_sub1 = make_search( 'start', 'never_existed' );
my $search_sub2 = make_search( 'start', 'never_existed' );


my @foo = qw/foo bar start baz end quz quz/;

my $count1 = $search_sub1->( \@foo );
my $count2 = $search_sub2->( \@foo );

print "count1 $count1 and count2 $count2\n";

أنا أيضا أكتب عن هذا في جعل مشغلي Flip-Flop الحصري.

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

يبدو أنه مصمم لبرامج نصية صغيرة جدًا مثل:

if (101 .. 200) { print; }

تنص الوثائق على أن هذا قصير ل

if ($. == 101 .. $. == 200) { print; }

بطريقة ما استخدام $. ضمني هناك (تشير الأدوات في تعليق أن هذا موثق أيضًا). يبدو أن الفكرة هي أن هذه الحلقة تعمل ذات مرة (حتى $. == 200) في حالة معينة من مترجم PERL ، وبالتالي لا داعي للقلق بشأن إعادة تعيين حالة .. نعال الشاطئ.

لا يبدو هذا المشغل مفيدًا جدًا في سياق أكثر عمومية لإعادة الاستخدام ، للأسباب التي حددتها.

حل بديل/اختراق/غش لحالتك الخاصة هو إلحاق القيمة النهائية إلى صفيفك:

sub search { 
  my $arr = shift;
  grep { !( /start/ .. /never_exist/ ) } @$arr, 'never_exist';
} 

سيضمن هذا أن يكون RHS of Range Operator صحيحًا في النهاية.

بالطبع ، هذا ليس بأي حال من الأحوال حل عام.

في رأيي ، هذا السلوك غير موثق بوضوح. إذا تمكنت من إنشاء تفسير واضح ، فيمكنك تطبيق تصحيح على perlop.pod عبر perlbug.

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

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

sub search {
  my $arr = shift;
  grep { !( /start/ || $_ eq "my magic reset string" ..
            /never_exist/ || $_ eq "my magic reset string" ) } 
      (@$arr, "my magic reset string");
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top