Perché hai bisogno di $ quando accedi agli elementi array e hash in Perl?
Domanda
Dato che array e hash possono contenere solo scalari in Perl, perché usare $ per dire all'interprete che il valore è uno scalare quando si accede a array o hash elements? In altre parole, supponendo che tu abbia un array @myarray
e un hash %myhash
, perché devi farlo:
$x = $myarray[1];
$y = $myhash{'foo'};
invece di fare semplicemente:
$x = myarray[1];
$y = myhash{'foo'};
Perché i precedenti sono ambigui?
Non sarebbe illegale il codice Perl se non fosse altro che un $ in quel posto? Ad esempio, in Perl non sono tutti illegali i seguenti?
@var[0];
@var{'key'};
%var[0];
%var{'key'};
Soluzione
Le fette non sono illegali:
@slice = @myarray[1, 2, 5];
@slice = @myhash{qw/foo bar baz/};
E sospetto che sia parte del motivo per cui è necessario specificare se si desidera ottenere un singolo valore dall'hash / array o meno.
Altri suggerimenti
Ho appena usato
my $x = myarray[1];
in un programma e, con mia sorpresa, ecco cosa è successo quando l'ho eseguito:
$ perl foo.pl
Flying Butt Monkeys!
Questo perché l'intero programma è simile al seguente:
$ cat foo.pl
#!/usr/bin/env perl
use strict;
use warnings;
sub myarray {
print "Flying Butt Monkeys!\n";
}
my $x = myarray[1];
Quindi myarray chiama una subroutine passandogli un riferimento a un array anonimo contenente un singolo elemento, 1.
Questa è un'altra ragione per cui hai bisogno del sigillo su un accesso array.
Il sigillo ti dà il tipo di ritorno del contenitore. Quindi, se qualcosa inizia con @
, sai che restituisce un elenco. Se inizia con $
, restituisce uno scalare.
Ora se c'è solo un identificatore dopo il sigillo (come $foo
o @foo
, allora è un semplice accesso variabile. Se è seguito da un [
, è un accesso su un array, se è seguito da un {
, è un accesso a un hash.
# variables
$foo
@foo
# accesses
$stuff{blubb} # accesses %stuff, returns a scalar
@stuff{@list} # accesses %stuff, returns an array
$stuff[blubb] # accesses @stuff, returns a scalar
# (and calls the blubb() function)
@stuff[blubb] # accesses @stuff, returns an array
Alcuni linguaggi umani hanno concetti molto simili.
Comunque molti programmatori lo hanno trovato confuso, quindi Perl 6 usa un sigillo invariante.
In generale il compilatore Perl 5 vuole sapere in fase di compilazione se qualcosa è nella lista o in un contesto scalare, quindi senza il sigillo iniziale alcuni termini diventerebbero ambigui.
Questo è Perl valido: @var[0]
. È una porzione di array di lunghezza uno. @var[0,1]
sarebbe una porzione di array di lunghezza due.
@var['key']
non è Perl valido poiché le matrici possono essere indicizzate solo da numeri e
gli altri due (%var[0] and %var['key']
) non sono validi Perl perché le sezioni hash usano {} per indicizzare l'hash.
@var{'key'}
e @var{0}
sono entrambi sezioni hash valide, comunque. Ovviamente non è normale prendere fette di lunghezza uno, ma è certamente valido.
Vedi la sezione slice di perldata perldoc per ulteriori informazioni sull'affettatura in Perl.
Le persone hanno già sottolineato che puoi avere sezioni e contesti, ma i sigilli sono lì per separare le cose che sono variabili da tutto il resto. Non è necessario conoscere tutte le parole chiave o i nomi delle subroutine per scegliere un nome di variabile sensibile. È una delle grandi cose che mi manca di Perl in altre lingue.
Mi viene in mente un modo
$x = myarray[1];
è ambiguo - e se volessi un array chiamato m?
$x = m[1];
Come puoi dirlo a parte una partita regex?
In altre parole, la sintassi è lì per aiutare l'interprete Perl, beh, interpretare!
In Perl 5 (da modificare in Perl 6) un sigillo indica il contesto della tua espressione.
- Desideri un particolare scalare da un hash, quindi è
$hash{key}
. - Vuoi che il valore di un determinato slot sia fuori da un array, quindi è
$array[0]
.
Tuttavia, come sottolineato da zigdon, sezioni sono legali. Interpretano quelle espressioni in un contesto elenco .
- Si desidera un elenco di 1 valore in un hash
@hash{key}
funziona -
Ma funzionano anche elenchi più grandi, come
@hash{qw<key1 key2 ... key_n>}
. -
Desideri un paio di slot da un array
@array[0,3,5..7,$n..$n+5]
funziona -
@array[0]
è un elenco di dimensioni 1.
Non c'è " hash context " ;, quindi né %hash{@keys}
né %hash{key}
hanno significato.
Quindi hai "@"
+ "array[0]"
< = > lt &; sigil = contesto > + < espressione di indicizzazione > come espressione completa.
Il sigillo fornisce il contesto per l'accesso:
-
$
significa contesto scalare (uno scalare variabile o un singolo elemento di un hash o di un array) -
@
significa contesto elenco (un intero array o una porzione di un hash o un array) -
%
è un intero hash
In Perl 5 hai bisogno dei sigilli ($ e @) perché l'interpretazione predefinita dell'identificatore bareword è quella di una chiamata di subroutine (eliminando così la necessità di usare & amp; nella maggior parte dei casi).