Quando il Perl inizializza automaticamente le variabili?
-
06-07-2019 - |
Domanda
Ecco un semplice Perl per contare il numero di volte in cui si verifica un valore in un array. Questo funziona senza alcun avviso.
use warnings;
use strict;
my @data = qw(1 1 2 3 4 5 5 5 9);
my %histogram;
foreach (@data)
{
$histogram{ Ecco un semplice Perl per contare il numero di volte in cui si verifica un valore in un array. Questo funziona senza alcun avviso.
$histogram{ Ecco un semplice Perl per contare il numero di volte in cui si verifica un valore in un array. Questo funziona senza alcun avviso.
use warnings;
use strict;
my @data = qw(1 1 2 3 4 5 5 5 9);
my %histogram;
foreach (@data)
{
$histogram{ Ecco un semplice Perl per contare il numero di volte in cui si verifica un valore in un array. Questo funziona senza alcun avviso.
<*>
Quando il corpo del loop viene modificato in
<*>
Perl avverte " Uso di valore non inizializzato in aggiunta " ;.
Cosa sta succedendo sotto il cofano? Perché il valore viene inizializzato quando fornito come operando all'operatore ++ e non inizializzato con l'operatore +?
}++;
}
Quando il corpo del loop viene modificato in
<*>
Perl avverte " Uso di valore non inizializzato in aggiunta " ;.
Cosa sta succedendo sotto il cofano? Perché il valore viene inizializzato quando fornito come operando all'operatore ++ e non inizializzato con l'operatore +?
} = $histogram{ Ecco un semplice Perl per contare il numero di volte in cui si verifica un valore in un array. Questo funziona senza alcun avviso.
use warnings;
use strict;
my @data = qw(1 1 2 3 4 5 5 5 9);
my %histogram;
foreach (@data)
{
$histogram{ Ecco un semplice Perl per contare il numero di volte in cui si verifica un valore in un array. Questo funziona senza alcun avviso.
<*>
Quando il corpo del loop viene modificato in
<*>
Perl avverte " Uso di valore non inizializzato in aggiunta " ;.
Cosa sta succedendo sotto il cofano? Perché il valore viene inizializzato quando fornito come operando all'operatore ++ e non inizializzato con l'operatore +?
}++;
}
Quando il corpo del loop viene modificato in
<*>
Perl avverte " Uso di valore non inizializzato in aggiunta " ;.
Cosa sta succedendo sotto il cofano? Perché il valore viene inizializzato quando fornito come operando all'operatore ++ e non inizializzato con l'operatore +?
} + 1;
Quando il corpo del loop viene modificato in
<*>
Perl avverte " Uso di valore non inizializzato in aggiunta " ;.
Cosa sta succedendo sotto il cofano? Perché il valore viene inizializzato quando fornito come operando all'operatore ++ e non inizializzato con l'operatore +?
}++;
}
Quando il corpo del loop viene modificato in
<*>Perl avverte " Uso di valore non inizializzato in aggiunta " ;.
Cosa sta succedendo sotto il cofano? Perché il valore viene inizializzato quando fornito come operando all'operatore ++ e non inizializzato con l'operatore +?
Soluzione
L'operatore + valuta sia il modulo a sinistra che il modulo a destra, quindi restituisce la somma di entrambi. La valutazione della chiamata hash non vede alcun contesto speciale.
L'operatore ++ ha qualche magia speciale integrata. Citando dalla manpage di perlop, riguardo all'operatore ++:
" undef " viene sempre trattato come un valore numerico e in particolare viene modificato su 0 prima dell'incremento (in modo che un post-incremento di un valore indefinito restituisca 0 anziché "undef").
modifica : per approfondire la differenza, ++ modifica il valore in atto, mentre + prende semplicemente i suoi argomenti come input. Quando + vede un valore indefinito, in genere qualcosa è andato storto, ma per ++, il tuo esempio di manipolazione dell'hash è molto tipico: l'utente vuole considerare undef come 0, invece di dover controllare e inizializzare ogni volta. Quindi sembra logico trattare questi operatori in questo modo.
Altri suggerimenti
Non è che Perl inizializzi necessariamente i valori, ma che non li avverte sempre. Non cercare di pensare a una regola per questo perché troverai sempre delle eccezioni e proprio quando pensi di averlo capito, la prossima versione di Perl cambierà gli avvisi su di te.
In questo caso, come ha affermato Harleqin, gli operatori di auto-incremento hanno un caso speciale.
Alcuni operatori omettono deliberatamente il "non inizializzato" avvertimento per la vostra convenienza perché sono comunemente usati in situazioni in cui 0 o "quot" " il valore predefinito per l'operando di sinistra o unico ha senso.
Questi sono: ++ e - (pre o post), + =, - =,. =, | =, ^ =, & amp; & amp; =, || =.
Nota che alcuni di questi danno erroneamente l'avvertimento quando usato su una variabile legata: vedi i test contrassegnati TODO in http://perl5.git.perl.org/perl.git/blob/HEAD:/t/op/assignwarn.t .
Come ha detto Brian: lo fa ancora, ti avverte. Gli avvertimenti ti informano su alcune manipolazioni con effetti che potresti non aver inteso.
Stai specificatamente chiedendo il valore di $ histogram {$ _}
, aggiungendo 1 ad esso e quindi assegnandolo allo stesso slot. È lo stesso modo in cui non mi aspetto che l'autovivificazione funzioni qui:
my $hash_ref = $hash_for{$key_level_1};
$hash_ref->{$key_level_2} = $value;
come fa qui:
$hash_for{$key_level_1}{$key_level_2} = $value;
La magia probabilmente non funziona come l'ottimizzazione. E l'ottimizzazione del compilatore noterebbe che a = a + 1
è la stessa cosa di a ++
, quindi se ci fosse un operatore di incremento nel linguaggio assembly, potrebbe invece usare quell'istruzione ottimizzata di fingere che fosse necessario per preservare il primo valore e quindi di sovrascriverlo perché non era effettivamente necessario.
L'ottimizzazione richiede ulteriore controllo e spese generali una volta per migliorare le prestazioni ad ogni corsa. Ma in un linguaggio dinamico non vi è alcuna garanzia che non si aggiunga un overhead alla stessa velocità che altrimenti si tenterebbe di ridurlo.