Kan Perl verwijzen naar een array met behulp van de naam?

I'm new to Perl and I understand you can call functions by name, like this: &$functionName();. However, I'd like to use an array by name. Is this possible?

Lange code:

sub print_species_names {
    my $species = shift(@_);
    my @cats = ("Jeffry", "Owen");
    my @dogs = ("Duke", "Lassie");

    switch ($species) {
        case "cats" {
            foreach (@cats) {
                print $_ . "\n";
            }
        }
        case "dogs" {
            foreach (@dogs) {
                print $_ . "\n";
            }
        }
    }
}

Zoekend kortere code gelijkend op dit:

sub print_species_names {
    my $species = shift(@_);
    my @cats = ("Jeffry", "Owen");
    my @dogs = ("Duke", "Lassie");

    foreach (@<$species>) {
        print $_ . "\n";
    }
}
1
toegevoegd de auteur Michael Carman, de bron
u kunt ook perldoc perleschermut lezen om betere manieren uit te leggen om datastructuren te maken, zoals gezien in de antwoorden die al zijn gepost
toegevoegd de auteur Joel Berger, de bron
alles is geopenbaard in perldoc perlref - zoek naar "symbolische verwijzingen"
toegevoegd de auteur evil otto, de bron

3 antwoord

Mogelijk? Ja. Aanbevolen? Nee . Over het algemeen is het gebruik van symbolische verwijzingen een slechte gewoonte. Gebruik in plaats daarvan een hash om uw arrays te bewaren. Op die manier kun je ze op naam opzoeken:

sub print_species_names {
    my $species = shift;
    my %animals = (
        cats => [qw(Jeffry Owen)],
        dogs => [qw(Duke Lassie)],
    );
    if (my $array = $animals{$species}) {
        print "$_\n" for @$array
    }
    else {
        die "species '$species' not found"
    }
}

Als je dat nog meer wilt verminderen, kun je het if/else-blok vervangen door:

    print "$_\n" for @{ $animals{$species}
        or die "species $species not found" };
15
toegevoegd
ach, het is niet zo erg om symbolische referenties te gebruiken ... maakt metaprogramming in perl mogelijk.
toegevoegd de auteur ennuikiller, de bron

U kunt iets dichtbij bereiken door een hash van arrayverwijzingen te gebruiken:

%hash = ( 'cats' => [ "Jeffry", "Owen"],
          'dogs' => [ "Duke", "Lassie" ] );

$arrayRef = $hash{cats};
4
toegevoegd

Je zou hier ook eval kunnen gebruiken:

foreach (eval("@$species")) {
        print $_ . "\n";
    }

Ik had duidelijk moeten maken dat je strikte richtlijnen moet uitschakelen om dit te laten werken. Dus de code omzeilen met gebruik van "nostrict" en "strikt" werken.

Dit staat bekend als een zachte referentie in perl.

0
toegevoegd
Kan string ("what was in $ species") niet gebruiken als een ARRAY-ref, terwijl "strict refs" in gebruik is bij ... Je hebt waarschijnlijk \ @ $ soorten bedoeld maar nog steeds, raad niet aan om eval te gebruiken voor dit soort dingen. En controleer in ieder geval op fouten als dat het geval is.
toegevoegd de auteur Eric Strom, de bron
strict pakt hier een belangrijke fout op. Als u strict uitschakelt, vindt de volgende transformatie plaats: "@ $ soorten" -> "@main :: dogs" -> '' -> eval ('') -> '' die zal stil nalaten te doen wat het OP wil, omdat de variabelen lexicaal zijn. Als de OP vervolgens overschakelde naar pakketvariabelen, wordt het nog erger. "@ $ soorten" -> "@main :: honden" -> 'Duke Lassie' -> eval ('Duke Lassie') -> probeert Lassie-> Duke() te bellen en hopelijk mislukt -> '' . Zoals ik in mijn eerste reactie zei, wilde je waarschijnlijk eval ('@'.$ soorten) die zou hebben gewerkt, maar dit benadrukt allemaal waarom je dat niet zou moeten doen.
toegevoegd de auteur Eric Strom, de bron
je moet natuurlijk afwenden om dit te laten werken ....
toegevoegd de auteur ennuikiller, de bron
Grappig ding is dat ik dit uit getest en het werkte perfect !!
toegevoegd de auteur ennuikiller, de bron
@ennuikiller, eval omzeilt strict in dit geval als het correct wordt gebruikt, en als je strict hebt uitgeschakeld, zou je foreach (@ $ species)) {...} kunnen gebruiken en bypass eval .
toegevoegd de auteur Ven'Tatsu, de bron