2012-06-29 26 views
14

Porównać użyciu perl -w -Mstrict:Co się dzieje, gdy moja() jest warunkowa?

# case Alpha 
print $c; 

...

# case Bravo 
if (0) { 
    my $c = 1; 
} 

print $c; 

...

# case Charlie 
my $c = 1 if 0; 
print $c; 

Alpha i Bravo zarówno narzekać globalny symbol nie mają wyraźnego nazwę pakietu, który należy się spodziewać. Ale Charlie nie daje takiego samego ostrzeżenia, tylko, że wartość jest niezainicjowany, który pachnie dużo jak:

# case Delta 
my $c; 
print $c; 

Co dokładnie dzieje się pod maską? (Nawet jeśli coś takiego nie powinno być nigdy zapisane w kodzie produkcyjnym)

+1

W przypadku Bravo, '$ C' jest leksykalnie zawężona do' if (0) ... 'bloku, i jest to błąd (pod 'use strict'), aby odnieść się do niego poza tym blokiem. – mob

+5

Nawiasem mówiąc, zachowanie 'my $ c = 1, jeśli 0; ... $ c ... 'jest oficjalnie niezdefiniowane (i udokumentowane jako takie), co oznacza, że ​​jest niedozwolone i może spowodować niepożądane zachowanie (np. awarię). Cóż, to się nie zawiesi, ale może :) – ikegami

+1

@ikegami hmm masz całkowitą rację, jest on wymieniony w sekcji "modyfikatory oświadczeń" w perlsyn. dobre przypomnienie! –

Odpowiedz

14

Możesz myśleć o deklaracji my jako o działaniu w czasie kompilacji i podczas wykonywania. Podczas kompilacji deklaracja my mówi kompilatorowi, aby zanotował, że symbol istnieje i będzie dostępny do końca bieżącego zakresu leksykalnego. Przypisanie lub inne użycie symbolu w tej deklaracji nastąpi w czasie wykonywania.

Więc przykład

my $c = 1 if 0; 

jest jak

my $c;   # compile-time declaration, initialized to undef 
$c = 1 if 0; # runtime -- as written has no effect 

Zauważ, że ten kompilacji/run-time rozróżnienie pozwala na pisanie kodu w taki sposób.

my $DEBUG; # lexical scope variable declared at compile-time 
BEGIN { 
    $DEBUG = $ENV{MY_DEBUG}; # statement executed at compile-time 
}; 

Teraz możesz zgadnąć, jaki jest wynik tego programu?

my $c = 3; 
BEGIN { 
    print "\$c is $c\n"; 
    $c = 4; 
} 
print "\$c is $c\n"; 
+0

NIESAMOWITA odpowiedź! Rozróżnienie kompilacji było brakującym kluczem. Wielkie dzięki! –

+4

'moje' ma efekt działania, jak mówisz, ale nie wspomniałeś o co chodzi! [Umieszcza dyrektywę na stosie, aby wyczyścić zmienną na wyjściu scope, następnie zwraca var jako l.] Ok, to chyba najlepsze, o czym nie wspomniałeś. :) – ikegami

6

mob's answer jest doskonałym wytłumaczeniem tego, co obecnie dzieje się (i dlaczego), ale nie należy zapominać, że perldoc perlsyn mówi nam:

UWAGA: zachowanie się my, state, lub our zmodyfikowany konstruktem warunkowym lub pętlowym o modyfikatorze instrukcji (na przykład my $x if ...) to undefined. Wartość zmiennej my może być undef, dowolną poprzednio przypisaną wartością lub ewentualnie cokolwiek innego. Nie polegaj na tym. Przyszłe wersje perla mogą zrobić coś innego, niż z wersji perl, którą wypróbujesz. Oto smoki.

Nie licz na ten wynik lub wyjaśnienie, że nadal jest prawdziwe w przyszłych wersjach Perla. (Chociaż to chyba będzie).

2

„My $ foo = val jeśli dyr” skonstruować i jego zachowanie niezdefiniowane ugryzł mnie wiele razy w ciągu roku.Chciałbym, żeby kompilator mógł po prostu go odrzucić (dlaczego zachować coś w języku, który ma niezdefiniowane zachowanie ?!), ale prawdopodobnie nie można tego zrobić ze względu na kompatybilność wsteczną lub z innych powodów. Najlepszym rozwiązaniem znalazłem jest zapobieganie jej perlcritic:

http://search.cpan.org/perldoc?Perl::Critic::Policy::Variables::ProhibitConditionalDeclarations

+0

Perlkrytyczny nigdy nie jest najlepszym rozwiązaniem. – tchrist

+3

Jaką mam alternatywę, jeśli chcę zapobiec przypadkowemu użyciu tego toksycznego konstruktu? –

Powiązane problemy