В Perl, когда вы возвращаете хэш из вложенного файла, каков «быстрый способ» получить определенное значение?

#perl #hash

Вопрос:

В Perl это работает, нет «простого» способа напрямую обращаться к хэшу, когда он возвращается из вложенной программы, или я что-то упускаю?

Мне бы хотелось чего-то подобного.

 print ( (hash()){One} ); # Not a thing!
 

Вы можете сделать это с помощью массива, так как возвращаемые значения представляют собой список.

 print ( (arr())[0] );
 

Но для хэша, который его не режет. Я придумал несколько способов, как заставить это работать.

 print ( ${{hash()}}{One} );
print ( 0 {hash()}->{One} );
 

Но они кажутся какими-то неубедительными. Я имею в виду, что это трудно прочитать, и ссылки на махинации неуместны для такой простой вещи.

Вот еще код для контекста.

 use strict;
use warnings;

### ARRAY
sub arr {
    my @arr = (
        1,
        2,
        3,  
    );
    return @arr;
}

print ( (arr())[0] ); #Output is 1; 

### HASH
sub hash {
    my %hash = (
        One   => 1,
        Two   => 2,
        Three => 3,
    ); 
    return %hash;
}

my %hash = hash();


#print ( (hash()){One} );       # Does not work
print ( $hash{One}  );          # Output is 1
print ( (hash())[0] );          # Output will be One, Two or Three
print ( (hash())[1] );          # Output will be 1, 2, 3
print ( ${{hash()}}{One} );     # Output is 1
print ( 0 {hash()}->{One} );    # Output is 1;
# 0  because Perl gives syntax error otherwise. Not sure why (Scalar context?) but one mystery at a time. 
 

Комментарии:

1. Подчиненные не могут возвращать массивы и хэши, только 0 или более скаляров (контекст списка) или один скаляр (скалярный контекст). Аналогично, массивы и хэши не могут быть переданы подчиненным, только 0 или более скаляров.

Ответ №1:

Подпрограммы возвращают не хэши, а список значений. Этот список можно преобразовать в хэш.

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

  {hash()}->{One}
 

Начало иногда необходимо для устранения неоднозначности ссылочного литерала хэша {...} из блока {...} 1 уровня оператора. Унарный плюс не является операцией и просто вызывает контекст выражения, тогда 0 как преобразует значение в число.

1. Хотя в данном конкретном случае двусмысленность связана с print(FILEHANDLE LIST) синтаксисом, в котором файловая ручка может быть заключена в фигурные скобки.

Если у вас есть контроль над функцией, пытающейся вернуть хэш, возможно, стоит подумать о том, чтобы вместо этого вернуть ссылку на хэш. Тогда ваш пример будет выглядеть так:

 sub hashref {
    # alternatively: "return { One => 1, ... };"
    my %hash = (
        One   => 1,
        Two   => 2,
        Three => 3,
    ); 
    return %hash;
    #      ^-- create a reference to the hash
}

my %hash = hashref()->%*;  # or "%{hashref()}". Note that this makes a copy

print( hashref()->{One} );  # can directly access keys
 

Комментарии:

1. Преимущество последнего подхода заключается в том, что он позволяет избежать необходимости «сглаживать» хэш в подпространстве и создавать новый хэш в вызывающем.

Ответ №2:

Следующий фрагмент кода демонстрирует использование ссылки на массив и ссылки на хэш.

Преимущество этого подхода заключается в отслеживании, когда вам приходится работать с большими массивами или хэшами-нет необходимости выделять память для копирования, экономит циклы процессора.

В некоторых случаях алгоритму может потребоваться создать копию того, что может быть легко достигнуто с помощью разыменования структуры данных (см. Пример).

 use strict;
use warnings;
use feature 'say';

### ARRAY
sub arr {
    my $ref_arr = [
        1,
        2,
        3,  
    ];
    return $ref_arr;
}

my $aref = arr();

say "
Array content:
    $aref->[0] $aref->[0]
    $aref->[1] $aref->[1]
    $aref->[2] $aref->[2]
";

my @array_copy = @$aref;

say "
Array copy content:
    $array_copy[0] $array_copy[0]
    $array_copy[1] $array_copy[1]
    $array_copy[2] $array_copy[2]
";

### HASH
sub hash {
    my $ref_hash = {
        One   => 1,
        Two   => 2,
        Three => 3,
    }; 
    return $ref_hash;
}

my $href = hash();

say "
Hash content:
    $href->{Three}: $href->{Three}
    $href->{Two}:   $href->{Two}
    $href->{One}:   $href->{One}
";

my %hash_copy = %$href;

say "
Hash copy content:
    $hash_copy{One}:   $hash_copy{One}
    $hash_copy{Two}:   $hash_copy{Two}
    $hash_copy{Three}: $hash_copy{Three}
";
 

Выход

 Array content:
        $aref->[0] 1
        $aref->[1] 2
        $aref->[2] 3


Array copy content:
        $array_copy[0] 1
        $array_copy[1] 2
        $array_copy[2] 3


Hash content:
        $href->{Three}: 3
        $href->{Two}:   2
        $href->{One}:   1


Hash copy content:
        $hash_copy{One}:   1
        $hash_copy{Two}:   2
        $hash_copy{Three}: 3