Domanda

Ho una funzione che accetta una variabile e un array associativo, ma non riesco a farli passare nel modo giusto. Penso che questo abbia qualcosa a che fare con le dichiarazioni di funzioni, tuttavia non riesco a capire come funzionano in Perl. C'è un buon riferimento per questo e come posso ottenere ciò di cui ho bisogno?

Dovrei aggiungere che deve essere passato per riferimento.

sub PrintAA
{
    my $test = shift;
    my %aa   = shift;
    print $test . "\n";
    foreach (keys %aa)
    {
        print 

Ho una funzione che accetta una variabile e un array associativo, ma non riesco a farli passare nel modo giusto. Penso che questo abbia qualcosa a che fare con le dichiarazioni di funzioni, tuttavia non riesco a capire come funzionano in Perl. C'è un buon riferimento per questo e come posso ottenere ciò di cui ho bisogno?

Dovrei aggiungere che deve essere passato per riferimento.

<*> . " : " . $aa{

Ho una funzione che accetta una variabile e un array associativo, ma non riesco a farli passare nel modo giusto. Penso che questo abbia qualcosa a che fare con le dichiarazioni di funzioni, tuttavia non riesco a capire come funzionano in Perl. C'è un buon riferimento per questo e come posso ottenere ciò di cui ho bisogno?

Dovrei aggiungere che deve essere passato per riferimento.

<*>} . "\n"; $aa{

Ho una funzione che accetta una variabile e un array associativo, ma non riesco a farli passare nel modo giusto. Penso che questo abbia qualcosa a che fare con le dichiarazioni di funzioni, tuttavia non riesco a capire come funzionano in Perl. C'è un buon riferimento per questo e come posso ottenere ciò di cui ho bisogno?

Dovrei aggiungere che deve essere passato per riferimento.

<*>} = $aa{

Ho una funzione che accetta una variabile e un array associativo, ma non riesco a farli passare nel modo giusto. Penso che questo abbia qualcosa a che fare con le dichiarazioni di funzioni, tuttavia non riesco a capire come funzionano in Perl. C'è un buon riferimento per questo e come posso ottenere ciò di cui ho bisogno?

Dovrei aggiungere che deve essere passato per riferimento.

<*>} . "+"; } }
È stato utile?

Soluzione

Passa il riferimento anziché l'hash stesso. Come in

PrintAA("abc", \%fooHash);

sub PrintAA
{
  my $test = shift;
  my $aaRef = shift;

  print $test, "\n";
  foreach (keys %{$aaRef})
  {
    print 

Passa il riferimento anziché l'hash stesso. Come in

<*>

Vedi anche perlfaq7: Come posso passare / restituire un {Function, FileHandle, Array, Hash, Method, Regex}?

, " : ", $aaRef->{

Passa il riferimento anziché l'hash stesso. Come in

<*>

Vedi anche perlfaq7: Come posso passare / restituire un {Function, FileHandle, Array, Hash, Method, Regex}?

}, "\n"; } }

Vedi anche perlfaq7: Come posso passare / restituire un {Function, FileHandle, Array, Hash, Method, Regex}?

Altri suggerimenti

Questo codice funziona:

#!/bin/perl -w

use strict;

sub PrintAA
{
    my($test, %aa) = @_;
    print $test . "\n";
    foreach (keys %aa)
    {
        print 

Questo codice funziona:

my $test = shift;
my(%aa) = @_;

Il punto chiave è l'uso del contesto dell'array nell'istruzione my () 'nella funzione.


  

Che cosa fa effettivamente l'attività nel contesto dell'array?

In breve, lo fa funzionare correttamente.

Significa che il primo valore nella matrice di argomenti @_ è assegnato a $ test , e gli elementi rimanenti sono assegnati all'hash % aa . Dato il modo in cui l'ho chiamato, c'è un numero dispari di elementi nel @_ , quindi una volta che il primo elemento è assegnato a $ test , c'è un numero pari di articoli disponibili da assegnare a % aa , con il primo elemento di ciascuna coppia come chiave ('aaa', 'bbb', 'ccc' nel mio esempio), e il secondo è il valore corrispondente.

Sarebbe possibile sostituire % aa con @aa , nel qual caso l'array avrebbe 6 elementi al suo interno. Sarebbe anche possibile sostituire % aa con $ aa e, in tal caso, la variabile $ aa conterrebbe il valore 'aaa' e i valori rimanenti in @_ verrebbero ignorati dall'assegnazione.

Se si omettono le parentesi attorno all'elenco delle variabili, Perl rifiuta di compilare il codice. Una delle risposte alternative ha mostrato la notazione:

Reference found where even-sized list expected at xx.pl line 18.
...
Use of uninitialized value in concatenation (.) or string at xx.pl line 13.

Questo è praticamente equivalente a quello che ho scritto; la differenza è che dopo le due istruzioni my , @_ contiene solo 6 elementi in questa variante, mentre nella singola versione my , rimane contiene 7 elementi.

Ci sono sicuramente altre domande in SO sul contesto dell'array.


  

In realtà, non stavo chiedendo di my ($ test,% aa) = @_; stavo chiedendo di my (% hash) = ('aaa' = > ; 1, 'bbb' = > 'balls', 'ccc' = > \ & amp; PrintAA); contro my% hash = {'aaa' = > 1, ...};

La differenza è che la notazione {...} genera un riferimento hash e la notazione (...) genera un elenco, che si associa a un hash (al contrario di ref hash). Allo stesso modo, [...] genera un riferimento array e non un array.

In effetti, cambia il codice 'principale' in modo che sia: my (% hash) = {...}; e ricevi un errore di runtime (ma non di compilazione) - tratta i numeri di riga con cautela poiché ho aggiunto codici alternativi al mio file:

<*> . " : " . $aa{

Questo codice funziona:

<*>

Il punto chiave è l'uso del contesto dell'array nell'istruzione my () 'nella funzione.


  

Che cosa fa effettivamente l'attività nel contesto dell'array?

In breve, lo fa funzionare correttamente.

Significa che il primo valore nella matrice di argomenti @_ è assegnato a $ test , e gli elementi rimanenti sono assegnati all'hash % aa . Dato il modo in cui l'ho chiamato, c'è un numero dispari di elementi nel @_ , quindi una volta che il primo elemento è assegnato a $ test , c'è un numero pari di articoli disponibili da assegnare a % aa , con il primo elemento di ciascuna coppia come chiave ('aaa', 'bbb', 'ccc' nel mio esempio), e il secondo è il valore corrispondente.

Sarebbe possibile sostituire % aa con @aa , nel qual caso l'array avrebbe 6 elementi al suo interno. Sarebbe anche possibile sostituire % aa con $ aa e, in tal caso, la variabile $ aa conterrebbe il valore 'aaa' e i valori rimanenti in @_ verrebbero ignorati dall'assegnazione.

Se si omettono le parentesi attorno all'elenco delle variabili, Perl rifiuta di compilare il codice. Una delle risposte alternative ha mostrato la notazione:

<*>

Questo è praticamente equivalente a quello che ho scritto; la differenza è che dopo le due istruzioni my , @_ contiene solo 6 elementi in questa variante, mentre nella singola versione my , rimane contiene 7 elementi.

Ci sono sicuramente altre domande in SO sul contesto dell'array.


  

In realtà, non stavo chiedendo di my ($ test,% aa) = @_; stavo chiedendo di my (% hash) = ('aaa' = > ; 1, 'bbb' = > 'balls', 'ccc' = > \ & amp; PrintAA); contro my% hash = {'aaa' = > 1, ...};

La differenza è che la notazione {...} genera un riferimento hash e la notazione (...) genera un elenco, che si associa a un hash (al contrario di ref hash). Allo stesso modo, [...] genera un riferimento array e non un array.

In effetti, cambia il codice 'principale' in modo che sia: my (% hash) = {...}; e ricevi un errore di runtime (ma non di compilazione) - tratta i numeri di riga con cautela poiché ho aggiunto codici alternativi al mio file:

<*>} . "\n"; } } my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \&PrintAA ); PrintAA("test", %hash);

Il punto chiave è l'uso del contesto dell'array nell'istruzione my () 'nella funzione.


  

Che cosa fa effettivamente l'attività nel contesto dell'array?

In breve, lo fa funzionare correttamente.

Significa che il primo valore nella matrice di argomenti @_ è assegnato a $ test , e gli elementi rimanenti sono assegnati all'hash % aa . Dato il modo in cui l'ho chiamato, c'è un numero dispari di elementi nel @_ , quindi una volta che il primo elemento è assegnato a $ test , c'è un numero pari di articoli disponibili da assegnare a % aa , con il primo elemento di ciascuna coppia come chiave ('aaa', 'bbb', 'ccc' nel mio esempio), e il secondo è il valore corrispondente.

Sarebbe possibile sostituire % aa con @aa , nel qual caso l'array avrebbe 6 elementi al suo interno. Sarebbe anche possibile sostituire % aa con $ aa e, in tal caso, la variabile $ aa conterrebbe il valore 'aaa' e i valori rimanenti in @_ verrebbero ignorati dall'assegnazione.

Se si omettono le parentesi attorno all'elenco delle variabili, Perl rifiuta di compilare il codice. Una delle risposte alternative ha mostrato la notazione:

<*>

Questo è praticamente equivalente a quello che ho scritto; la differenza è che dopo le due istruzioni my , @_ contiene solo 6 elementi in questa variante, mentre nella singola versione my , rimane contiene 7 elementi.

Ci sono sicuramente altre domande in SO sul contesto dell'array.


  

In realtà, non stavo chiedendo di my ($ test,% aa) = @_; stavo chiedendo di my (% hash) = ('aaa' = > ; 1, 'bbb' = > 'balls', 'ccc' = > \ & amp; PrintAA); contro my% hash = {'aaa' = > 1, ...};

La differenza è che la notazione {...} genera un riferimento hash e la notazione (...) genera un elenco, che si associa a un hash (al contrario di ref hash). Allo stesso modo, [...] genera un riferimento array e non un array.

In effetti, cambia il codice 'principale' in modo che sia: my (% hash) = {...}; e ricevi un errore di runtime (ma non di compilazione) - tratta i numeri di riga con cautela poiché ho aggiunto codici alternativi al mio file:

<*>

In alternativa:

sub PrintAA
{
    my $test       = shift;
    my %aa         = @_;
        print $test . "\n";
        foreach (keys %aa)
        {
                print 

In alternativa:

<*>

La cosa che ti manca fondamentalmente è che un array associativo non è un singolo argomento (anche se un riferimento di array associativo è, come nella risposta di Paul Tomblin).

. " : " . $aa{

In alternativa:

<*>

La cosa che ti manca fondamentalmente è che un array associativo non è un singolo argomento (anche se un riferimento di array associativo è, come nella risposta di Paul Tomblin).

} . "\n"; $aa{

In alternativa:

<*>

La cosa che ti manca fondamentalmente è che un array associativo non è un singolo argomento (anche se un riferimento di array associativo è, come nella risposta di Paul Tomblin).

} = $aa{

In alternativa:

<*>

La cosa che ti manca fondamentalmente è che un array associativo non è un singolo argomento (anche se un riferimento di array associativo è, come nella risposta di Paul Tomblin).

} . "+"; } }

La cosa che ti manca fondamentalmente è che un array associativo non è un singolo argomento (anche se un riferimento di array associativo è, come nella risposta di Paul Tomblin).

Sembra che dovresti passare un riferimento a un hash.

sub PrintAA
{
   my $test = shift;
   my $aa = shift;
   if (ref($aa) != "HASH") { die "bad arg!" }
   ....
}

PrintAA($foo, \%bar);

Il motivo per cui non puoi fare

my %aa = shift;

è perché Perl appiattisce tutti gli argomenti in una subroutine in un elenco, @_. Ogni elemento viene copiato, quindi passare per riferimento evita anche quelle copie.

Come al solito ci sono diversi modi. Ecco cosa Best Practices del Perl , di cui la maggior parte venerata puntatori di stile, ha da dire sul passaggio dei parametri alle funzioni:

Usa un hash di argomenti con nome per qualsiasi subroutine che ha più di tre parametri

Ma dato che ne hai solo due, potresti scappare;) passando direttamente in questo modo:

my $scalar = 5;
my %hash = (a => 1, b => 2, c => 3);

func($scalar, %hash)

E la funzione è definita in questo modo:

sub func {
    my $scalar_var = shift;
    my %hash_var = @_;

    ... Do something ...
}

Potrebbe essere più utile se tu potessi mostrare del codice.

Tutti i metodi di cui sopra funzionano, ma è sempre stato così che preferivo fare cose del genere:

sub PrintAA ($\%)
{
    my $test       = shift;
    my %aa         = ${shift()};
    print "$test\n";
    foreach (keys %aa)
    {
        print "

Tutti i metodi di cui sopra funzionano, ma è sempre stato così che preferivo fare cose del genere:

PrintAA("test", %hash);

Nota: ho anche modificato un po 'il tuo codice. Le stringhe tra virgolette doppie interpreteranno " $ test " come il valore di $ test anziché la stringa effettiva '$ test' , quindi non hai bisogno di tanti . s.

Inoltre, mi sbagliavo su come funzionano i prototipi. Per passare un hash, usa questo:

PrintAA("test", %$ref_to_hash);

Per stampare un riferimento all'hash, usare questo:

<*>

Naturalmente, ora non puoi modificare l'hash a cui fa riferimento $ ref_to_hash perché stai inviando una copia, ma puoi modificare un % hash grezzo perché lo stai passando come riferimento.

: $aa{

Tutti i metodi di cui sopra funzionano, ma è sempre stato così che preferivo fare cose del genere:

<*>

Nota: ho anche modificato un po 'il tuo codice. Le stringhe tra virgolette doppie interpreteranno " $ test " come il valore di $ test anziché la stringa effettiva '$ test' , quindi non hai bisogno di tanti . s.

Inoltre, mi sbagliavo su come funzionano i prototipi. Per passare un hash, usa questo:

<*>

Per stampare un riferimento all'hash, usare questo:

<*>

Naturalmente, ora non puoi modificare l'hash a cui fa riferimento $ ref_to_hash perché stai inviando una copia, ma puoi modificare un % hash grezzo perché lo stai passando come riferimento.

}\n"; $aa{

Tutti i metodi di cui sopra funzionano, ma è sempre stato così che preferivo fare cose del genere:

<*>

Nota: ho anche modificato un po 'il tuo codice. Le stringhe tra virgolette doppie interpreteranno " $ test " come il valore di $ test anziché la stringa effettiva '$ test' , quindi non hai bisogno di tanti . s.

Inoltre, mi sbagliavo su come funzionano i prototipi. Per passare un hash, usa questo:

<*>

Per stampare un riferimento all'hash, usare questo:

<*>

Naturalmente, ora non puoi modificare l'hash a cui fa riferimento $ ref_to_hash perché stai inviando una copia, ma puoi modificare un % hash grezzo perché lo stai passando come riferimento.

} = "$aa{

Tutti i metodi di cui sopra funzionano, ma è sempre stato così che preferivo fare cose del genere:

<*>

Nota: ho anche modificato un po 'il tuo codice. Le stringhe tra virgolette doppie interpreteranno " $ test " come il valore di $ test anziché la stringa effettiva '$ test' , quindi non hai bisogno di tanti . s.

Inoltre, mi sbagliavo su come funzionano i prototipi. Per passare un hash, usa questo:

<*>

Per stampare un riferimento all'hash, usare questo:

<*>

Naturalmente, ora non puoi modificare l'hash a cui fa riferimento $ ref_to_hash perché stai inviando una copia, ma puoi modificare un % hash grezzo perché lo stai passando come riferimento.

}+"; } }

Nota: ho anche modificato un po 'il tuo codice. Le stringhe tra virgolette doppie interpreteranno " $ test " come il valore di $ test anziché la stringa effettiva '$ test' , quindi non hai bisogno di tanti . s.

Inoltre, mi sbagliavo su come funzionano i prototipi. Per passare un hash, usa questo:

<*>

Per stampare un riferimento all'hash, usare questo:

<*>

Naturalmente, ora non puoi modificare l'hash a cui fa riferimento $ ref_to_hash perché stai inviando una copia, ma puoi modificare un % hash grezzo perché lo stai passando come riferimento.

Gli argomenti alle funzioni vengono appiattiti in un singolo array (@_). Quindi di solito è più facile passare gli hash per funzionare come riferimento.

Per creare un HASH:

my %myhash = ( key1 => "val1", key2 => "val2" );

Per creare un riferimento a quel HASH:

my $href = \%myhash

Per accedere a quell'hash come riferimento;

%$href

Quindi nel tuo sub:

my $myhref = shift;

keys %$myhref;

Tutte le altre risposte qui finora mi sembrano piuttosto complicate. Quando scrivo la funzione Perl di solito " espandere " tutti gli argomenti passati nella prima riga della funzione.

sub someFunction {
    my ( $arg1, $arg2, $arg3 ) = @_;

È simile ad altre lingue, in cui si dichiarano funzioni come

... someFunction ( arg1, arg2, arg3 )

E se lo fai in questo modo e passi l'hash come ultimo argomento, starai bene senza alcun trucco o magia speciale. Per esempio:.

sub testFunc {
    my ( $string, %hash ) = @_;
    print "$string $hash{'abc'} $hash{'efg'} $string\n";
}

my %testHash = (
    'abc' => "Hello",
    'efg' => "World"
);
testFunc('!!!', %testHash);

L'output è come previsto:

!!! Hello World !!!

Questo funziona perché gli argomenti Perl vengono sempre passati come una matrice di valori scalari e se si passa un hash, i suoi valori / coppie chiave vengono aggiunti a quella matrice. Nell'esempio sopra, gli argomenti passati alla funzione come array ( @_ ) sono in effetti:

'!!!', 'abc', 'Hello', 'efg', 'World'

e '!!!' è semplicemente assegnato a % string , mentre % hash " swallows " tutti gli altri argomenti, interpretando sempre uno come chiave e il successivo come valore (fino a quando tutti gli elementi non sono esauriti).

Non è possibile passare più hash in questo modo e l'hash non può essere il primo argomento, poiché altrimenti inghiottirebbe tutto e lascerebbe tutti gli altri argomenti non assegnati.

Ovviamente lo stesso vale per l'array come ultimo argomento. L'unica differenza qui è che gli array non distinguono tra chiavi e valori, per loro tutti gli argomenti lasciati sono valori e vengono semplicemente inseriti nell'array.

Usa il sottotitolo folowing per ottenere hash o hashref - qualunque cosa sia passata :)

sub get_args { ref( 

Usa il sottotitolo folowing per ottenere hash o hashref - qualunque cosa sia passata :)

printAA($firstarg,somearg=>1, anotherarg=>2)

Chiama la tua funzione in questo modo:

printAA($firstarg,{somearg=>1, anotherarg=>2})

O in questo modo (non importa):

my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \PrintAA );

PrintAA("test", %hash);

O anche così (non importa):

<*>

Cheers!

[0] ) ? shift() : ( @_ % 2 ) ? {} : {@_}; } sub PrintAA { my $test = shift; my $aa = get_args(@_);; #then $aa->{somearg} #do something $aa->{anotherearg} #do something }

Chiama la tua funzione in questo modo:

<*>

O in questo modo (non importa):

<*>

O anche così (non importa):

<*>

Cheers!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top