#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