Передача Perl Hash по ссылке плюс скалярная переменная

Я пытаюсь передать из Main.pl в подпрограмму (в ReadConfigFile.pm) хэш по ссылке и скалярное значение. Скалярная переменная — это путь к файлу конфигурации, и после открытия этого файла я хочу заполнить хэш некоторыми его значениями. Как мне передать хэш по ссылке и скаляр, чтобы у меня были значения хэша, доступные для использования в Main.pl

Я много читал, но не могу заставить это работать. Я понимаю, что не могу = @_; в моей подпрограмме, поскольку это создает новый хеш.

Я пробовал следовать методу прототипа, он заполняет хеш нормально, но в Main.pl хэш пустой.

Main.pl

# Read the config file.  Return 3 scalars and a hash
my %apps;
my ($schema, $directory, $staticFile) = readConfigFile(\%apps, $configFilePath);

my %app_list = %apps;  # ive tried this in, out and in a variety of states

foreach my $name (sort keys %app_list) {
    print "\nMAIN $name";
}
# this is empty

ReadConfigFile.pm

sub readConfigFile (\%$) {
my ($apps_ref, $configFilePath) = @_;

# also tried 
# $apps_ref = shift but then configFilePath is empty
# linearray is each line from open config file split by :

$apps_ref{$lineArray[1]}{id} = $lineArray[1];
$apps_ref{$lineArray[1]}{name} = $lineArray[2];
$schema = $lineArray[1];
$directory = $lineArray[1];
$staticFile = $lineArray[1];

return ($schema, $directory, $staticFile);  

configFile.txt

APP:1101:ACTIVITY
APP:1102:EVENTS
APP:1103:PERFORMANCE
APP:1104:LOCATION
STATIC_FILE:static_file.sql
SCHEMA:CAASS
DIRECTORY:CAASS

Я хочу вернуть 3 скалярные переменные и хэш, чтобы я мог использовать их в Main.pl и передавать другим сабвуферам.

Я также попытался передать только имя файла конфигурации и вернуть 4 переменные, 3 скаляра и хэш.

Я ожидаю, что кто-то взломает это за считанные минуты, но я просто не могу найти комбинацию \ и @, % и $, чтобы это сработало.

Спасибо за любую помощь или идеи.

Редактировать 1: Main.pl

my %apps;
my ($schema, $directory, $staticFile) = readConfigFile(\%apps, $configFilePath);

foreach my $name (sort keys %apps) {
    print "\nMAIN $name";
}

Реадконфигфиле

sub readConfigFile () {
my $apps_ref = shift;
my $configFilePath = $_[0];
#Fill It
$apps_ref{$lineArray[1]}{id} = $lineArray[1];
$apps_ref{$lineArray[1]}{name} = $lineArray[2];

# This shows results
foreach my $name (sort keys %apps_ref) {
    print "\nreadConfigFile   $name";
}

Но ценности не возвращаются в Main.pl

edit 2: Так что мне все еще интересно, как это можно заставить работать. Но я напал на это по-другому, и это работает

Main.pl

my ($schema, $directory, $staticFile, %apps) = readConfigFile($configFilePath);

foreach my $name (sort keys %apps) {
    print "\nMAIN $name";
}

Реадконфигфиле

sub readConfigFile () {
my $configFilePath = $_[0];
my %apps;
#Fill It
%apps{$lineArray[1]}{id} = $lineArray[1];
$apps{$lineArray[1]}{name} = $lineArray[2];

foreach my $name (sort keys %apps) {
    print "\nreadConfigFile   $name";
}

return ($schema, $directory, $staticFile, %apps);

Оба комплекта выключают выходное шоу.


person David Janes    schedule 04.06.2019    source источник
comment
Всегда используйте use strict; use warnings qw( all );!!! Нашел бы проблему   -  person ikegami    schedule 05.06.2019
comment
Все эти ошибки привлекли мое внимание, когда я добавил use strict; и использовать предупреждения; Без включения работало, так что вопросов бы не было!   -  person David Janes    schedule 05.06.2019


Ответы (1)


В Perl* нет неявной передачи по ссылке. Все передается одинаково - как список скаляров, по псевдониму (таким образом, при передаче самого хэша будет передан список его ключей и значений*). Но вы можете создать ссылку, передать ее, а затем разыменовать, чтобы использовать — и ссылки можно копировать без копирования базовой структуры.

use strict;
use warnings;
my %hash;
my $ref = \%hash;
my $copy = $ref;
$copy->{a} = 1;
print "$ref->{a}\n"; # also 1

Ссылки сохранят свою ссылочную структуру после присвоения my (...) = @_; или my $foo = shift; в подпрограмме.

use strict;
use warnings;

sub foo {
  my ($ref, $key) = @_;
  $ref->{$key} = 42;
}

my %hash;
foo(\%hash, 'foo');
print "$hash{foo}\n"; # 42

См. https://p3rl.org/REF для получения соответствующей документации по ссылкам на Perl.

Поскольку вы уже передаете ссылку, вам не нужен прототип (\%$): вы можете просто удалить его из определения подпрограммы.

*кроме прототипов, но в большинстве случаев их лучше избегать.

person Grinnz    schedule 04.06.2019
comment
Я не понимаю ваш код, но он становится немного более запутанным для меня, когда переменные передаются в подпрограмму и обратно. Не могли бы вы расширить свой ответ и показать мне, как получить 2 переменные из подпрограммы. Спасибо - person David Janes; 04.06.2019
comment
@DavidJanes Я добавил пример, это поможет? Убедитесь, что вы не используете () в определении подпрограммы, это все еще прототип и не делает то, что вы хотите. - person Grinnz; 04.06.2019
comment
Re В Perl нет неявной передачи по ссылке. Наоборот, все передается по ссылке. (Вы должны иметь в виду, что только скаляры могут быть переданы подпрограммам.) - person ikegami; 05.06.2019
comment
@ikegami Это то, что я пытался сказать, но, возможно, объяснил плохо - для этого нет возможности, потому что это всегда происходит, но только с переданными скалярами. - person Grinnz; 05.06.2019