У Perl можна посилатися на масив, використовуючи його назву?

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?

Довгий код:

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";
            }
        }
    }
}

Шукати коротший код, подібний до цього:

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

    foreach (@<$species>) {
        print $_ . "\n";
    }
}
1
додано Автор Michael Carman, джерело
Ви також можете прочитати perldoc perlreftut , щоб пояснити кращі способи створення структур даних, як відповіді, які вже були опубліковані
додано Автор Joel Berger, джерело
все відкрито в perldoc perlref - шукайте "символічні посилання"
додано Автор evil otto, джерело

3 Відповіді

Можливо? Так. Рекомендовано? Ні . Загалом, використання символічних посилань є поганою практикою. Замість цього використовуйте хеш, щоб утримувати ваші масиви. Таким чином ви можете переглянути їх за назвою:

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"
    }
}

Якщо ви хочете зменшити це ще більше, ви можете замінити блок if/else на:

    print "$_\n" for @{ $animals{$species}
        or die "species $species not found" };
15
додано
ах, це не так вже й погано використовувати символічні посилання .... робить метапрограмування в perl можливим.
додано Автор ennuikiller, джерело

Ви можете досягти чогось близького, використовуючи хеш-посилання на масив:

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

$arrayRef = $hash{cats};
4
додано

Ви також можете використовувати eval тут:

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

Я повинен був чітко давати зрозуміти, що для того, щоб це працювало, потрібно вимкнути суворі посилання. Так оточуючий код з використанням "nostrict" і використовуйте "строгі" роботи.

Це те, що відомо як м'які посилання в perl.

0
додано
Неможливо використати рядок ("будь-що в $ species") як архівний код ARRAY, а "суворі посилання" в ... Ви, мабуть, мали на увазі \ _ $ species але не рекомендуйте рядок eval для таких речей. І хоча б перевірити на наявність помилок, якщо ви це зробите.
додано Автор Eric Strom, джерело
strict тут виявляє важливу помилку. Якщо вимкнути строгий, то має місце наступне перетворення: "@ $ species" -> "@main :: dogs" -> '' -> eval ('') -> '' буде мовчки не в змозі зробити те, що ОП хоче, тому що змінні лексичні. Якщо OP потім переключився на змінні пакунків, речі стають ще гіршими. "@ $ species" -> "@main :: собаки" -> 'Duke Lassie' -> eval ('Duke Lassie') -> намагається викликати Lassie-> Duke() і, сподіваюся, не вдасться -> '' . Як я вже сказав у своєму першому коментарі, ви, мабуть, хотіли б eval ('@'.$ species) , які б працювали, але це все підкреслює, чому ви не повинні.
додано Автор Eric Strom, джерело
Ви, очевидно, повинні відмовитися від строго, щоб це працювало.
додано Автор ennuikiller, джерело
Смішно те, що я перевірив це, і він працював чудово !!
додано Автор ennuikiller, джерело
@ennuikiller, eval в такому випадку обходить суворо, якщо він використовується правильно, а якщо вимкнуто, ви можете використовувати foreach (@ $ species)) {...} і обхід eval .
додано Автор Ven'Tatsu, джерело