Насколько вы знаете о Perl-ссылках? Вы можете посмотреть несколько tutorials на Perl references.
Краткое пособие
Все три основных структур данных в Perl (скаляры, массивы и хэши) предназначены для хранения отдельных значений данных. Например, у меня есть массив сотрудников:
$employee_list[0] = "Bob";
$employee_list[1] = "Carol";
$employee_list[2] = "Ted";
$employee_list[3] = "Alice";
Да, есть четыре части данных в моем массиве, но в простом Perl, каждый элемент содержит только одно значение - первое имя. Что мне делать, если мне также нужна фамилия сотрудника или зарплата или должность? Нет простого способа сделать это в базовой структуре данных Perl.
Ссылки - это способ, позволяющий хранить более одной части данных в переменной Perl. Давайте посмотрим на полную запись сотрудника Боба:
$employee{FIRST} = "Bob";
$employee{LAST} = "Jones";
$employee{PAY} = "1400";
$employee{PHONE} = "1234";
Теперь, как я могу сжать всю эту информацию в $employee_list[0]
? .
Perl позволяет принимать ссылку на этот хэш %employee
(главным образом место в памяти, где хранится хэш Вы можете сделать это, поставив обратную косую черту перед ним:
$employee_list[0] = \%employee;
сейчас в этом один $employee_list[0]
слоте, у меня есть ссылка на хэш Perl, который имел все данные сотрудника Боба. Теперь вопрос в том, как я могу получить доступ к этой информации?
я могу получить доступ к информации в моей ссылке на разыменовании это.Вы что, поставив правильный sigil перед ссылкой:
$employee_reference = $employee_list[0];
%employee_hash = %$employee_reference;
print "Employee name is $employee_hash{FIRST} $employee_hash{LAST}\n";
Я сначала получить ссылку, то я могу разыменования его в новый %employee_hash
. Как только я это сделаю, я могу использовать информацию, находящуюся в хеше. Это большая работа. Посмотрите на $employee_reference
. Все, что я делаю с этим, получает ссылку, поэтому я могу разыменовать ее. Почему бы не вырезать этот шаг и не принять мое различие от $employee_list[0]
?
%employee_hash = %{ $employee_list[0] };
print "Employee name is $employee_hash{FIRST} $employee_hash{LAST}\n";
Примечание. Я использую фигурные скобки вокруг своей ссылки. Кудрявые скобки напоминают скобки вокруг уравнения. Они позволили Перлу понять, что делать в первую очередь.
Опять же, я ничего не делаю с %employee_hash
. Это просто место, где я могу бросить свой хэш, поэтому я могу его распечатать. Почему бы не разыменовать хэш и не получить значение определенного ключа за один шаг? Еще лучше. В одном шаге:
print "Employee name is "
. ${ $employee_list[0] }{FIRST} . " "
. ${ $employee_list[0] }{LAST} . "\n";
Я разыменования $employee_list[0]
в хэш и принимая этот хэш, и извлечение значения конкретного ключа все в том же шаге. Обратите внимание, что я использую $
вместо %
.
Как вы можете видеть, это может быстро усложниться. Тем не менее, Perl дает хороший способ представить эту чрезмерно сложную структуру:
print "Employee name is "
. $employee_list[0]->{FIRST} . " "
. $employee_list[0]->{LAST} . "\n";
Оператор ->
принимает разыменования для вас.
Это тоже нелепо, что я строил хэш, называемый %employee_hash
, просто чтобы сделать ссылку на него. Perl позволяет ссылаться на анонимный хешей и массивов.
$employee_list[0] = { LAST => "Jones", FIRST => "Bob",
SALARY => 1400, PHONE => "1234" }
Фигурные скобки для анонимных хэшей. Квадратные скобки для анонимные массивы. Они анонимны, потому что они не относятся к переменной, а просто относятся к хешу или массиву.
Data :: Dumper
Как вы можете себе представить, эти структуры данных могут быть довольно сложными. Например, я отслеживаю адрес сотрудника, но адрес состоит из улицы, города, штата и почтового индекса. Иногда на улице есть более одной линии. И что, если есть более одного адреса? Там нет причин, почему хеш или ссылки на массив не может содержать ссылку на другой хэш или массив:
$employee_list[0]->{NAME}->{FIRST} = "Bob";
$employee_list[0]->{NAME}->{LAST} = "Jones";
$employee_list[0]->{ADDRESS}->[0]->{TYPE} = "Business";
$employee_list[0]->{ADDRESS}->[0]->{STREET}->[0] = "123 Mockingbird Lane";
$employee_list[0]->{ADDRESS}->[0]->{STREET}->[1] = "Tower 2";
$employee_list[0]->{ADDRESS}->[0]->{CITY} = "Beantown";
$employee_list[0]->{ADDRESS}->[0]->{STATE} = "MA";
Как вы можете видеть $ employee_list [0] указывает на ссылки на хэш сотрудника. Этот хэш имеет «ИМЯ», «АДРЕС» и другие ключи, заполненные данными. Поле NAME
является ссылкой на другой хэш, который имеет два ключа: FIRST
и LAST
. Поле ADDRESS
на самом деле является ссылкой на массив адресов. И каждая из этих записей массива является ссылкой на хэш. Представьте, что вы пытаетесь отладить эту структуру данных!
Data::Dumper представляет собой модуль, который будет анализировать через самые сложные структуры данных и распечатать их для вас:
use Data::Dumper;
[...]
print "Employee Dump: " . Dumper \@employee . "\n";
Это будет печатать всю структуру всех сотрудников в массиве сотрудников.
Если вы не знаете, что @{$value{$key}}
, вы можете легко запустить дамп на нем:
print Dumper $value{$key} . "\n";
Декодировании Вашей программы
Давайте пройдемся по линиям один за другим:
%Routings =();
my $dbh = DBI->connect('dbi:ODBC:SQL')
or die "Couldn't open Databaxe: $DBI::errstr; stopped";
Вы инициализировали хэш с именем и создали объект DBI, который представляет соединение с вашей базой данных. connect
- это подпрограмма, определенная в Perl как часть класса DBI. Все классы состоят из множества подпрограмм Perl, которые работают с объектами, созданными этим классом. Эти подпрограммы делятся на конструкторы и методы. Конструкторы создают ссылку на сложную структуру данных, которая представляет объект. Методы - это подпрограммы, которые могут работать на этом объекте. Представьте себе нашу запись сотрудника:
$employee = Person::Employee->new;
$employee->first_name("Bob");
Первая строка создает $employee
объект из моего Person::Employee
класса. Это объект $employee
- это просто ссылка на хэш, содержащий информацию о моем сотруднике. Итак, моя подпрограмма new
является конструктором .
Во второй строке используется подпрограмма first_name
, которая позволяет мне установить имя сотрудника. Эта подпрограмма называется Метод или иногда Функция участника.
Итак, возвращаясь к программе, мы создали объект, который представляет наше соединение с базой данных. Если вы хотите, вы можете использовать Data::Dumper
, чтобы распечатать структуру этого объекта , если это поможет вам понять его немного лучше. Это просто ссылка на хэш.
my $query= $dbh->prepare("SELECT Code, Setup, Process, ProcessID FROM ROUTING");
$query->execute() or die "Couldn't execute statement: $DBI::errstr; stopped";
я теперь подготовить мой SQL заявление, которое я хочу выполнить. После того, как я его подготовил, я его выполнил. Выполнение - это действительно то, что попадает в базу данных. Обратите внимание, что мой prepare
- это метод для дескриптора базы данных $dbi
, но это также конструктор, потому что он создал объект $query
.
Я использую этот объект $query
для фактического выполнения моего запроса. Опять же, не бойтесь использовать Data::Dumper
, чтобы распечатать его.
while (my ($Code, $setup, $process, $processid) = $query->fetchrow_array()){
push (@{ $Routings{$Code} }, [ $ProcessID, $Setup, $Process ]);
}
Давайте упростить этот бит:
while (my @fetched_row = $query->fetchrow_array()){
my ($Code, $setup, $process, $processid) = @fetched_row;
push (@{ $Routings{$Code} }, [ $ProcessID, $Setup, $Process ]);
}
fetchrow_array
это подпрограмма, которая выбирает одну строку из моего запроса в виде массива столбцов. Эта подпрограмма представляет собой метод объекта $query
, который я создал выше. Все, что я делаю, - это извлекать каждую строку из моей базы данных и помещать ее в четыре скалярные переменные Perl.
Последняя строка немного сложна. Запомнить мой хэш, который я инициализировал? По-видимому, каждый ключ в этом хеше - это ссылка на массив значений. Хэш вводится на основе $Code
, который я набрал выше, и это указывает на массив из трех элементов, состоящий из $ProcesssID
, $Setup
и $Process
. Мы могли бы переписать третью строчку так:
my @temp_array = ($ProcessID, $Setup, $Process);
my @temp_routing_array = @{ $Routings{Code} }; #Dereferencing the $Routing{$Code} array
push(@temp_routing_array, \@temp_array); #Pushing a reference into my array
$Routing{$Code} = \@temp_routing_array; #Creating a reference again
[ $ProcessID, $Setup, $Process ]
является просто создание ссылки на анонимный массив. Это сэкономит нам трудность создания @temp_array
, а затем нажав ссылку @temp_array
на мой @temp_routing_array
.
И, пока мы на нем, произошла ошибка в вашем коде. Я получаю $setup
, $process
и $processid
, но я храню (смотрю корпус с именами переменных) $Setup
, $Process
и $ProcessID
.
Теперь мы добираемся до петли foreach и еще одной ошибки. Какая ценность $Code
? Он не имеет значения, поскольку переменная $Code
существует только в цикле while
выше. Когда вы объявляете переменную с my
, значение этой переменной теряется после того, как вы покинете блок кода.
Эта ошибка, и вышеприведенная ошибка могла быть поймана, если у вас были use strict;
и use warnings;
в верхней части вашей программы.
Давайте посмотрим на эту петлю:
foreach (@{ $Routings{$Code} }) {
my $ProcessCodeID = @$_[0];
my $SetupMins = @$_[1];
my $ProcessMins = @$_[2];
}
Этот foreach
цикл использует устаревший стиль, в котором вы предполагаете, вы перекручивание через переменную $_
. Это сбивает с толку, и большинство людей научились не использовать его. Давайте перепишем его:
my @routing_code_ref_array = @{ $Routings{$Code} };
foreach my $routing_array_ref (@routing_code_ref_array) {
my @routing_array = @{ $routing_array_ref };
my $ProcessCodeID = $routing_array[0];
my $SetupMins = $routing_array[1];
my $ProcessMins = $routing_array[2];
}
Помните, что $Routings{$Code}
является ссылкой на массив. В моей первой строке я разыгрываю это. В исходном коде разыменование произошло в цикле foreach
. Не только было $Routings{$Code}
ссылка на массив, но каждая запись в этом массиве была ссылкой на другой массив. Это array of arrays.
Итак, каждая запись в моем @routing_code_ref_array
является ссылкой на другой массив, который я разыменовываю еще раз. Теперь я просто беру значения каждого элемента массива и помещаю его в обычные скалярные переменные Perl.
Хватит уже!
Извините за длинное объяснение, но у вас есть код, который затрагивает ссылки, классы, методы, конструкторы, объекты и целую кучу довольно продвинутых тем Perl. Как и несколько ошибок, которые я указал. Ошибки, которые могли быть пойманы с помощью пары стандартных прагм Perl: use strict;
и use warnings;
.
Если есть все, что вы можете забрать это:
- Такие вещи, как
@$foo{$bar}[4]
или @{ $foo{bar} }[4]
или (более правильно) ${ $foo{bar} }[4]
или (более четко) $foo{bar}->[4]
ссылки на более сложные структуры данных. В базовых структурах данных Perl может храниться только один элемент за раз. Используя ссылки на другие структуры данных, вы можете иметь массивы массивов или массивов хешей или хешей хешей или хэшей массивов или даже массивы хешей хешей массивов хешей. Не паникуйте и не пытайтесь разбирать эти вещи изнутри. Иногда бывает проще, если вы можете обрабатывать особенно сложную структуру данных в нескольких строках.
- Если вы собираетесь столкнуться с сложными структурами,
Data::Dumper
- ваш друг. Он быстро выявит структуру этих чрезмерно сложных структур и поможет вам отладить проблемы с вашей программой.
- Используйте
strict
и warnings
в ваших программах. Они заберут много программных ошибок. Как я уже сказал, я нашел два, связанных как с областью действия локальной переменной, так и с ошибкой в случае имен переменных. Это также великая идея стандартизировать имена переменных. Эти два метода - camelCasing и используются только символы подчеркивания и строчные буквы. Таким образом, вы знаете, что это всегда $foo_bar
и никогда $Foo_Bar
или $FooBar
или $fooBar
. Старый стандарт был верблюжьим корпусом, первая буква которого была строчной буквой. Новый стандарт использует строчные буквы и подчеркивает только.
Большое вам спасибо. Я пропустил разницу в верхнем и нижнем регистре. Теперь это работает. Я также ценю объяснение и помогаю очистить свой код. Большое спасибо. – user1340197
Если вы не хотите идти на поводу (по общему признанию, очень мало проблем) добавления 'use Data :: Dumper' к вашему коду, вы можете видеть то же самое, проверяя хеши и массивы с помощью команды« x »в perl отладчик. Пройдите код до тех пор, пока соответствующая переменная не будет заполнена, а затем введите 'x @ {$ value {$ key}}'. Отладчик использует Data :: Dumper для отображения структуры массива или хэша (он действительно работает лучше с хеш-ссылками). –