Perl как передать хеш в функцию

Обновлено: 02.07.2024

Хэш - ассоциативный массив, т.к. доступ к данным осуществляется при помощи ключа, ассоциированного со значением. Хэши начинаются с префикса % : %hash . Для работы с с хэш-массивами нужно, как и в обычных массивах, использовать разыменовывающий префикс $ : $hash = серая;

Хэш можно определить несколькими способами:

Если используется пробел при определении элемента хэша, то этот пробел лучше поставить в одинарные кавычки $hash = серая;

Добавить элементы в хеш можно так:

Удалить элемент из хэша можно при помощи функции delete :

Функция delete может вызываться для среза хэша, что приводит к удалению всех указанных ключей: delete @hash; см. perlfunc(1)

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

Для перебора элементов не очень большого хеша можно воспользоваться foreach:

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

Цикл foreach перебирает заранее построенный список ключей, поэтому после начала цикла он ничего не знает о добавленных или удаленных ключах, ключи, добавляемые внутри цикла, не включаются автоматически в список перебираемых ключей, а удаленные внутри цикла ключи не удаляются из этого списка.

Содержимое хэша можно вывести и так:

Вывод хэша одной строкой.

можно воспользоваться функцией map : print map $hash\n"> keys %hash;

функция map позволяет работать с элементами в произвольном порядке, в этом случае создается список строк(ключ => значение), передаваемый функции print . Если сохранить хэш во временном массиве, то он будет выведен как строка:

Запускаем программу чтения почтового ящика: bash-2.03$ ./1.pl /usr/home/vovka/mbox

Для перебора элементов хэша в порядке вставки, т.к. keys и each выводят элементы хеша неупорядоченно, можно воспользоваться модулем Tie::IxHash

Хэши с несколькими значениями, ассоциированными одним ключом. Т.к. скалярные величины, содержащиеся в хэше, могут быть ссылками(которые могут быть скалярами), то ассоциировать несколько значений одним ключом можно сохранив в $hash($key) ссылку на массив со значениями, ассоциированными с ключом $key . Операции с хэшами(вставка, удаление, перебор и проверка существования(undef)) переписываются для операций с массивами( push , splice и foreach ). Пример, реализующий вставку в хэш(обрабатывает выходные данные команды who(1) и выводит краткий список пользователей с терминалами, на которых они зарегестрированы):

в строке push содержится версия $tty = $tty для многозначного хэша. Все имена терминалов интерполируются в строке print @<$ttys> .

Инвертирование хэша производится при помощи функции reverse , в котором ассоциированные значения исходного хэша являются ключами и наоборот. Воспользуемся списковой эквивалентностью хэшей. В списковом контексте reverse иетерпретирует %hash как список и меняет местами составляющие его элементов. Например: имеем хэш %Glavfish = ("seledka"=>"mokraia","skat"=>"elektricheskij") , если его интерпретировать как список, то получим следующее ("seledka","mokraia","skat","elektricheskij") , после инвертирования список выглядит так: ("elektricheskij","skat","mokraia","seledka") , интерпретация его как хэша дает следующее: ("elektricheskij"=>"skat","mokraia"=>"seledka") . Пример программы, которая на название предмета выдает его свойство и наоборот:

Сортировка ключей по алфавиту ассоциированных значений: Чтобы сэкономить память, можно воспользоваться таким кодом:

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

Если keys вызывается для хэша, ключи которого представляют собой ссылки, то возвращаемые ей ссылки не работают. Ключи преобразуются в строки, т.е. интерпретируются так, словно они заключены в кавычки, при работе со ссылками они теряют свои свойства. После преобразования в строку ссылка имеет вид

Преобразованную ссылку нельзя вернуть к прежнему виду, т.к. она из ссылки превратилась в строку. Нужно создать специальный хэш, ключами которого являются ссылки, преобразованные в строки, и значениями - настоящие ссылки.Можно воспользоваться модулем Tie::RefHash . Пример показывает использование объектов ввода/вывода для работы с файловыми манипуляторами.

Если в качестве ключа использована неопределенная величина undef , то она преобразуется в пустую строку. undef является вполне допустимым значением в хэше. Но при выборке значения для ключа, отсутствующего в хэше perl выдаст undef . Проверить наличие ключа можно так: exist($hash); определенность ассоциированного значения: defined($hash); истинность: if($hash); . Иногда undef нужно сохранять в кэше, т.е. ключ есть, но с ним не связано ничего полезного, например программа, определяющая размер файлов из переданного списка:

Этот код позволяет пропустить несуществующие и нулевые файлы, но записанные в исходном списке.


Как можно хеш положить в строку? Например проблема:

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

самый простой и топорный вариант - сделать хеш с соответствиями типа я => ya сплитить строчки и заменять элементы полученного массива на нужные. что-то на подобие:

Переменные окружения, использующие встроенные хэши и массивы %INC , %SIG , %ENV , %FORM<> .

%INC содержит имена файлов, включаемых командами do и require. Ключ имя файла, значение путь до включаемого файла. Массив @INC содержит список дирректорий, которые просматривает perl для выполнения команд do, require или use.

%ENV содержит значения переменных среды(окружения), заданных на момент запуска сценария(скрипта). Ключами обычно бывают имена переменных среды(но их состав зависит от операционной системы), изменение этих значений вызовет изменение окружения для процессов потомков. программа выдает:

Непосредственно из скрипта элементы хэша %ENV можно вызывать $ENV или $ENV , смотря что нужно вызывать.

%FORM содержит данные, вводимые из формы методом POST: html форма такая:

<form action="/cgi-bin/1.pl" method="post">
<input type="text" name="name1" size=10 maxlength=10>
<input type="text" name="name2" size=10 maxlength=10>
<input type="text" name="name3" size=10 maxlength=10>
<input type="submit" value="send">
<input type="reset" value="reset"></form>

Если мы введем в поле name1 qwe, name2 rty, name3 asd и нажмем send, то через STDIN передаются данные в виде: name1=qwe&name2=rty&name3=asd и содержимое хэша

У меня есть функция, которая принимает переменную и ассоциативный массив, но я не могу заставить их пройти правильно. Я думаю, что это как-то связано с объявлениями функций, однако я не могу понять, как они работают в Perl. Есть ли хорошая ссылка для этого и как мне выполнить то, что мне нужно?

Я должен добавить, что это должно быть передано по ссылке.

Передайте ссылку вместо самого хеша. Как в

Этот код работает:

Ключевым моментом является использование контекста массива в операторе my () в функции.

Что на самом деле делает бизнес контекста массива?

Вкратце, это заставляет его работать правильно.

Это означает, что первое значение в массиве аргументов @_ присваивается $test , а остальные элементы присваиваются хешу %aa . Учитывая то, как я это назвал, в @_ есть нечетное количество элементов, поэтому, как только первый элемент назначен для $test , будет доступно четное количество элементов, которые можно назначить для %aa , причем первый элемент каждой пары будет ключ ('aaa', 'bbb', 'ccc' в моем примере), а второй - соответствующее значение.

Можно было бы заменить %aa на @aa , и в этом случае массив будет содержать 6 элементов. Также было бы возможно заменить %aa на $aa , и в этом случае переменная $aa будет содержать значение 'aaa', а остальные значения в @_ будут игнорироваться присваиванием.

Это в значительной степени эквивалентно тому, что я написал; разница состоит в том, что после двух операторов my @_ содержит только 6 элементов в этом варианте, тогда как в одной версии my он все еще содержит 7 элементов.

На самом деле, я не спрашивал о my($test, %aa) = @_; , я спрашивал о my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \&PrintAA ); против my %hash = < 'aaa' => 1, . >;

Разница в том, что нотация <. >генерирует хэш-ссылку, а нотация (. ) генерирует список, который отображается на хеш (в отличие от хеш-ссылки). Точно так же [. ] генерирует массив ref, а не массив.

Действительно, измените «основной» код так, чтобы он читал: my (% hash) = <. >; и вы получаете ошибку во время выполнения (но не во время компиляции) - обрабатывайте номера строк с осторожностью, так как я добавил альтернативные кодировки в свой файл:

В качестве альтернативы:

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

Похоже, вы должны передать ссылку на хеш.

Причина, по которой вы не можете сделать

потому что Perl объединяет все аргументы подпрограммы в один список, @_. Каждый элемент копируется, поэтому передача по ссылке также позволяет избежать этих копий.

Как обычно, есть несколько способов. Вот что Perl Best Practices, наиболее уважаемый из указателей стилей, говорит о передаче параметров в функции:

Использовать хеш именованных аргументов для любой подпрограммы, которая имеет более трех параметров

Но так как у вас есть только два, вы можете уйти;) с передачей их прямо так:

И функция определяется так:

Это может быть более полезным, если вы могли бы показать некоторый код.

Все вышеперечисленные методы работают, но я всегда предпочитал делать такие вещи:

Примечание: я также немного изменил ваш код. Строки Perl в двойных кавычках будут интерпретировать "$test" как значение $test , а не как фактическую строку '$test' , поэтому вам не нужно так много . s.

Кроме того, я был неправ относительно того, как работают прототипы. Чтобы передать хеш, используйте это:

Чтобы напечатать ссылку на хеш, используйте это:

Конечно, теперь вы не можете изменить хеш, на который ссылается $ref_to_hash , потому что отправляете копию, но вы можете изменить необработанный %hash , потому что вы передаете его в качестве ссылки.

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

Это похоже на другие языки, где вы объявляете функции как

И если вы сделаете это таким образом и передадите хеш в качестве последнего аргумента, у вас все будет хорошо без каких-либо уловок или особой магии. Например.:

Результат, как и ожидалось:

Это работает, потому что в Perl аргументы всегда передаются в виде массива скалярных значений, и если вы передаете хеш, его значение/пары ключей добавляются в этот массив. В приведенном выше примере аргументы, переданные функции в виде массива ( @_ ), на самом деле:

а также '. ' просто присваивается %string , в то время как %hash «проглатывает» все остальные аргументы, всегда интерпретируя один как ключ, а следующий как значение (пока все элементы не будут использованы).

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

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

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

Чтобы создать HASH:

Чтобы создать ссылку на этот HASH:

Чтобы получить доступ к этому хешу по ссылке;

Итак, в вашем сабе:

Используйте следующую подпрограмму, чтобы получить хеш или hashref - что бы ни пропустили :)

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

Я должен добавить, что он должен быть передан по ссылке.

передайте ссылку вместо самого хэша. Как в

этот код работает:

ключевым моментом является использование контекста массива в My() 'statement' в функции.

что на самом деле делает бизнес контекста массива?

емко, Это заставляет его работать правильно.

это означает, что первое значение @_ массив аргументов назначена $test , а остальные элементы присваиваются хэшу %aa . Учитывая, как я звонил. это есть нечетное число элементов @_ , поэтому, как только первый элемент назначен $test , есть четное количество элементов, доступных для назначения %aa , причем первый элемент каждой пары является ключом ("aaa", "bbb", " ccc " в моем примере), а второй-соответствующим значением.

можно было бы заменить %aa С @aa в этом случае массив будет иметь 6 элементов в нем. Также можно было бы заменить %aa С $aa , и в это случай, переменная $aa будет содержать значение "aaa", а остальные значения в @_ будет проигнорировано поручение.

это почти равносильно тому, что я написал; разница в том, что после двух my отчетность, @_ содержит только 6 элементов в этом варианте, тогда как в один my версия, она по-прежнему содержит 7 элементов.

есть, безусловно, другие вопросы в так о контексте массива.

на самом деле, я не спрашивал о my($test, %aa) = @_; я спрашивал о my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \&PrintAA ); и my %hash = < 'aaa' => 1, . >;

разница в том, что < . >нотация генерирует хэш-ссылку и ( . ) нотация генерирует список, который сопоставляется с хэшем (в отличие от хэша ref). Аналогично. [ . ] создает ссылку на массив, а не массив.

действительно, измените "основной" код, чтобы он читал: my (%hash) = < . >; и вы получаете ошибки во время выполнения (но не во время компиляции) - обрабатывайте номера строк с осторожностью, так как я добавил альтернативные кодировки в свой файл:

то, что вам принципиально не хватает, - это то, что ассоциативный массив не является единственным аргументом (хотя ссылка на ассоциативный массив, как в ответе пола Томблина).

похоже, что вы должны передать ссылку на хэш.

причина, по которой вы не можете сделать

это потому, что Perl сглаживает все аргументы подпрограммы в один список, @_. Каждый элемент копируется, поэтому передача по ссылке также позволяет избежать этих копий.

все вышеперечисленные методы работают, но я всегда предпочитал делать так:

Примечание: я также немного изменил ваш код. Строки с двойными кавычками Perl интерпретируют "$test" значению $test а не фактическая строка '$test' , так что вам не нужно так много . s.

кроме того, я ошибался в том, как работают прототипы. Чтобы передать хэш, используйте следующее:

для печати хэш-ссылки используйте это:

конечно, теперь вы не можете изменить хэш, на который ссылается $ref_to_hash потому что вы отправляете копию, но вы можете изменить raw %hash потому что вы передаете его в качестве ссылки.

как обычно есть несколько способов. Вот что Perl Лучшие Практики, что наиболее почитаемый из указателей стиля, должен сказать о передаче параметров функциям:

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

но так как у вас есть только два, вы могли бы уйти;) с передачей их прямо так:

и функция определена как это:

было бы более полезно, если бы вы могли показать некоторый код.

аргументы функций сглаживаются в один массив (@_). Поэтому обычно проще всего передавать хэши для работы по ссылке.

чтобы создать хэш:

создать ссылку на этот хэш:

для доступа к этому хэшу по ссылке;

Итак, в вашем sub:

все остальные ответы здесь до сих пор кажутся мне довольно сложными. Когда я пишу функцию Perl, я обычно "разворачиваю" все переданные аргументы в первой строке функции.

это похоже на другие языки, где вы объявляете функции как

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

выход в ожидалось:

это работает, потому что в аргументах Perl всегда передаются как массив скалярных значений, и если вы передаете хэш, это ключевое значение/пары добавляются в этот массив. В приведенном выше примере аргументы передаются функции как array ( @_ ) на самом деле:

и '. 'просто назначается %string , а %hash "проглатывает" все остальные аргументы, всегда интерпретируя один как ключ, а следующий как значение (пока не будут использованы все элементы вверх.)

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

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

используйте folowing sub, чтобы получить хэш или hashref-все, что прошло:)

Автор статьи не дает никаких гарантий, что код приведенный в ней будучи "преобразованный" с помощью Copy/Past заработает. Все примеры работали на момент написания статьи.

Инициализация (очистка) хэша

Самый быстрый способ очистки - это присвоение пустого списка.

Реализация

Примечание

Часто спрашивают, как инициализировать указатель на хэш (hash ref). Указатель - это скалярная переменная и инициализируется она соответствующим образом. Например:

Добавление пары ключ/значение в хэш

В примерах, приведенных ниже, кавычки вокруг ключей могут быть опущены, если ключи - идентификаторы.

Решение

Указатель на хэш:

Решение

Добавление нескольких пар ключ/значение в хэш

Решение

Эти операции эквивалентны, просто второй более читаем.

Копирование хэшей

Решение

Удаление одной пары ключ/значение

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

Решение

Указатель на хэш:

Перебор всех пар ключ/значение

Пример, приведенный ниже, печатает все пары ключ/значение.

Решение

Использование функции each с циклом while. Обратите внимание, что each переберет пары в случайном порядке, но порядок будет совпадать с перебором с помощью функций keys и values.

Для указатель на хэш небольшое отличие:

Решение

Использование функции keys с циклом for

Пример

Получение размера хэша

Решение

Solution

Использование указателей на хэш

Решение

Функция строящая хэш из хэшей и возвращающая указатель на хэш

Решение

Доступ к хэшу из хэшей с помощью указателей. Вывод значений

Решение

Решение

Функция строящая хэш из хешей из хешей и возвращающая указатель на хэш

Решение

Доступ к хэшу из хэшей из хэшей с помощью указателей. Вывод значений.

Решение

Вывод ключей и значений из хэша, полученного с помощью указателя

Решение

Определение существования значения в хэше

Решение

Пример

Допустим, мы выполнили SQL запрос, который может вернуть записи, содержащие значение NULL. Перед тем как использовать результат запроса нам необходимо проверить, ОПРЕДЕЛЕНЫ ли полученные значения. Обратите внимание, функция sql_fetch_hashref() соединяется с сервером баз данных, подготавливает запрос, выполняет его и получает указатель на хэш с помощью DBI функции fetchrow_hashref() .

Читайте также: