Викиучебник ruwikibooks https://ru.wikibooks.org/wiki/%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0 MediaWiki 1.47.0-wmf.17 first-letter Медиа Служебная Обсуждение Участник Обсуждение участника Викиучебник Обсуждение Викиучебника Файл Обсуждение файла MediaWiki Обсуждение MediaWiki Шаблон Обсуждение шаблона Справка Обсуждение справки Категория Обсуждение категории Полка Обсуждение полки Импортировано Обсуждение импортированного Рецепт Обсуждение рецепта Задача Обсуждение задачи TimedText TimedText talk Модуль Обсуждение модуля Event Event talk Некоторые сведения о Perl 5 0 13443 269872 264846 2026-08-27T05:41:49Z ScriptMaster 15708 /* Запуск программ Perl */ корректировка 269872 wikitext text/x-wiki {{Название учебника |Название=Некоторые сведения о Perl 5 |Лого=Perl-logo.svg |Описание=Справочное пособие |Готовность = 100% |Категория = Программирование|Тип=Многостраничный }} {{цитата|There's More Than One Way To Do It}} {{Содержание |Тема = 10 | # [[/Типы данных|Типы данных]] # [[/Операции и выражения|Операции и выражения]] # [[/Операторы|Операторы]] # [[/Ввод и вывод|Ввод и вывод]] # [[/Форматированный вывод|Форматированный вывод]] # [[/Ссылки|Ссылки]] # [[/Функции и процедуры|Функции и процедуры]] # [[/Пакеты, библиотеки и модули|Пакеты, библиотеки и модули]] # [[/Объектно-ориентированное программирование в Perl|Объектно-ориентированное программирование в Perl]] # [[/Работа со строками и регулярные выражения|Работа со строками и регулярные выражения]] # [[/Perl XS|Perl XS]] # [[/POD|POD]] # [[/CPAN|CPAN]] # [[/UTF-8|UTF-8]] # [[/Приложения|Приложения]] }} Данная книга является справочным пособием по языку программирования Perl 5. Ожидается, что читатель имеет некоторый опыт программирования, но не требует опыт программирования в Perl. В книге приведены основные сведения, касающиеся языка Perl, и некоторые паттерны программирования в нем. Рассмотрены возможности языка и основные модули интерпретатора perl. Книгу следует читать последовательно, так как более старшие главы предполагают знания и понимания предыдущих. Местами материал может забегать вперед. В ранних главах книги весь код нарочно приводится без директивы <source lang="perl"> use strict; </source> чтобы читатель сначала увидел, как язык программирования выглядит без нее. Тем не менее, в реальных проектах эта директива должна обязательно включаться, так как она убережет начинающего Perl-программиста от глупых ошибок. Материал книги вращается вокруг 5-й версии языка и не привязан к конкретной версии интерпретатора, тем не менее, если в тексте это будет важно для контекста, об этом будет сказано отдельно. == Почему Perl == [[File:Source code in Perl.png|thumb|400px|Фрагмент функции на языке Perl. Для понимания контекста, функция подчищает HTML-код от ненужного содержимого по некоторым правилам]] Язык Perl был разработан в 1987 году и имеет много архаичных черт, характерных для языков программирования того времени. Язык прошёл очень большой путь в своём развитии, поэтому нынешнее его состояние по синтаксису очень сильно отличается от его ранних версий. Язык в первую очередь разрабатывался как альтернатива [[AWK]] и Bourne Shell, то есть он придумывался для написания исполняемых сценариев. Если вы пришли к этому языку будучи Python-программистом, ко многому придется очень долго привыкать. Несмотря на кажущуюся заброшенность, язык продолжает развиваться и имеет большое число последователей из разных областей: от рядового системного администратора до специалистов в областях естественных наук (математиков, физиков, химиков, биологов и др.). Perl довольно сложный язык, особенно если вы никогда не программировали на Си, не писали на языках командных оболочек и не пробовали писать что-нибудь для AWK. Perl это определённо не тот язык, который стоит изучать первым. Этот язык обладает следующими преимуществами: * встроенные и очень простые средства для работы со сложными структурами; * свободный синтаксис, благодаря чему одна и та же задача может решаться разными способами; * огромное число готовых библиотек, решающих самые разные задачи; * встроенная поддержка регулярных выражений — гордость Perl. Регулярные выражения в Perl работают в среднем очень быстро. Это отчасти связано с тем, что язык разрабатывался как анализатор больших текстовых массивов; * поддержка различных парадигм программирования: процедурная, объектно-ориентированная (ООП) и функциональная; * динамическая типизация; * автоматическое выделение и освобождение памяти (по методу подсчета ссылок); * кроссплатформенность; * свободное распространение интерпретатора и открытость его исходного кода; * Perl предустановлен практически в каждом дистрибутиве *nix системы, что позволяет без дополнительных действий запускать свои программы. Perl хорошо зарекомендовал себя в следующих областях: * системное администрирование: автоматизация процессов, сбор информации и формирование отчетов; * фильтры электронной почты; * когда-то на нём активно писали CGI-сценарии, но сейчас первенство в этом забрал больше PHP; * написание всевозможных web-серверов; * написание web-клиентов. На Perl можно писать прототипы для больших программ, а также можно постигать основы системного программирования. == Краткая история языка == [[File:FOSDEM 2015 Larry Wall and Camelia the Perl6 logo.jpg|thumb|300px|Ларри Уолл в 2015 году]] Язык Perl создал в 1987 году программист компании Unisys Ларри Уол (лингвист по образованию). В какой-то момент Ларри понадобился простой инструмент для создания отчётов о содержании многочисленных текстовых файлов в среде Unix. На тот момент существовало два широко используемых инструмента для разбора текстовых файлов — Sed и AWK, — но к разочарованию Ларри он упёрся в их ограничение на число одновременно открытых файловых дескрипторов. Отчасти это и побудило Ларри разработать новый язык для извлечения и составления отчётов — Perl (''Practical Extraction аnd Report Language''). По мере роста потребностей Ларри, он добавлял в язык все больше и больше возможностей, и Perl уже перестал быть похожим на язык для сбора отчетов, а становился языком общего назначения. Со временем Ларри сделал язык и код интерпретатора открытым для всех желающих, после чего язык стремительно начал набирать популярность. Пика популярности он достиг в 2000–2006 годах. В эти годы и была написана внушительная часть модулей CPAN. [[File:FOSDEM 2015 Perl camel.jpg|thumb|left|300px|Маскотом языка Perl является верблюд. Выбор животного обусловлен первой книгой о Perl ''Programming Perl'', на обложке которой был изображен верблюд — не слишком красивое, но очень выносливое животное, способное выполнять тяжёлую работу]] На становление Perl повлияли в первую очередь Sed, AWK, Си, Basic, LISP и языки командной оболочки (в первую очередь Bourne Shell). Быстрому распространению языка способствовало то, что он уже был похож на языки, которые многие знали. В первую очередь синтаксис Perl напоминал помесь языка командной оболочки и Си; программы Perl не требовалось компилировать, точнее они компилировались на ходу или, другими словами, не нужно было предварительно составлять make-файлы, что экономило время; язык мог решать повседневные задачи, которые решались в командной оболочке, при этом код выполнялся в разы быстрее, а синтаксический анализатор уберегал программиста от ошибок. Активно пользуясь языком, многие программисты направляли Ларри свои пожелания, которые в основном удовлетворялись. В 1990-х, по мере развития сети Интернет, язык становится излюбленным инструментом Web-разработки для создания динамических сайтов. '''История в датах:''' * 18 декабря 1987 года анонсирована и выпущена версия 1.0. * В 1988 году был выпущен Perl 2, основным нововведением которого был переработанный механизм регулярных выражений. * В 1989 году был выпущен Perl 3. В язык была добавлена возможность обработки двоичных данных. * В 1991 году была выпущена «Верблюжья книга» — ''Programming Perl'', которая де-факто стала учебником по языку Perl. В то же время была поднята версия языка до Perl 4. Разработка этой версии остановилась в 1993 году на версии 4.036. * В 1994 начата разработка Perl 5. 17 октября 1994 года выпущен Perl 5.000, который включал в себя полностью переписанный интерпретатор, появилось ООП, ссылки, локальные <code>my</code> переменные, также появились модули, предоставляющие механизм расширения языка без переписывания интерпретатора. * 26 октября 1995 начала работу CPAN (''Comprehensive Perl Archive Network'' — «Всеобъемлющая сеть архивов Perl»). * 15 мая 1997 года выпущен Perl 5.004, в котором введен пакет UNIVERSAL, дающий корневой класс, который наследуют все остальные. * 22 июня 1998 года выпущен Perl 5.005 с улучшенным процессором регулярных выражений. * 22 марта 2000 года выпущен Perl 5.6, в который включена поддержка 64-битных архитектур. Была изменена система ведения версий: за версией 5.005_63 последовала 5.5.640. Было принято соглашение применять к стабильным версиям интерпретатора четные номера версий. * В 2000 году Ларри выступил с призывом активно обсуждать следующую версию языка — Perl 6. * В 2001 году начата работа над окончательной спецификацией к Perl 6. * 18 июля 2002 года выпущен Perl 5.8 и с этого момента интерпретатор начал получать ежегодные обновления. Версия 5.8 улучшила поддержку Unicode; увеличила числовую точность. * В 2004 начата работа над Synopsis — ряд документов, ставший впоследствии спецификацией к Perl 6. * В феврале 2005 года Отриус Тан начала работу над Pugs — первой реализацией Perl 6 на Haskell, но в 2006 году проект заглох. * 18 декабря 2007 года, в день 20-летней годовщины Perl 1.0, была выпущена версия Perl 5.10.0. Эта версия включает нововведения из Perl 6: операторы <code>given..when</code>; обновление регулярных выражений; операция <code>~~</code>. Примерно в это же время начата серьезная работа по реализации Perl 6 — ''Rakudo Perl''. * 12 апреля 2010 года вышел Perl 5.12.0. Главным нововведение стала полная поддержка Unicode 5.2. * 14 мая 2011 выпущен Perl 5.14. В языке появилась встроенная поддержка JSON. [[Файл:Perl history.svg|800px|center|Вехи развития языка Perl|frameless]] == Краткий обзор учебника == [[Файл:Bookshelf at home (556126063).jpg|right|350px|thumb|Этот учебник всего лишь капля в море]] Программа на языке Perl очень похожа на сценарий командной оболочки, т.е. в ней нет точки входа из функции <code>main()</code>, как например в языке Си или Java. Код начинает интерпретироваться с первой строки по последнюю как он записан в файле. Программа Perl может быть разнесена в несколько файлов, при этом точкой входа является один из них — запускающий файл. Другие файлы подключаются к запускающему файлу с помощью управляющих директив. Perl заимствует ряд свойств из языков программирования командных оболочек Unix. Все переменные маркируются ведущими знаками (''сигилами''), которые точно выражают тип данных переменной в этом контексте. Важно, что эти знаки позволяют переменным быть интерполированным в строках. Perl обладает множеством встроенных функций, которые обеспечивают инструментарий, часто используемый для программирования оболочки, например сортировку или вызов системных служб. В главе «[[{{Root book name}}/Типы данных|Типы данных]]» вводятся три основных типа данных: скаляр, массив и хеш. Общая структура Perl в общих чертах ведёт своё начало от языка Си. Perl — процедурный по своей природе, имеет переменные, выражения присваивания, блоки кода, отделяемые фигурными скобками, управляющие структуры и функции. Perl является императивным языком, т.е. программа строится из последовательности операторов, определяющих действия. Простые операторы представляют выражения, которые состоят из одной и более операций. Главы «[[{{Root book name}}/Операции и выражения|Операции и выражения]]» и «[[{{Root book name}}/Операторы|Операторы]]» знакомят читателя с правилами построения операторов и основами синтаксиса языка. Программа на любом языке программирования служит, чтобы принять данные, обработать их и отдать некоторый результат. Глава «[[{{Root book name}}/Ввод и вывод|Ввод и вывод]]» рассказывает как реализуется простейший ввод данных и вывод их на устройство вывода. Вывод данных может быть сформирован в удобочитаемую для человека форму. Глава «[[{{Root book name}}/Форматированный вывод|Форматированный вывод]]» описывает инструменты Perl для форматированного вывода. Для построения сложных структур в язык были введены ссылки, которые хранят адреса на ячейки в памяти, позволяющие произвольно осуществлять доступ к данным программы. В главе «[[{{Root book name}}/Ссылки|Ссылки]]» рассказано, как работать с данными по ссылкам. Сложные программы обычно разбиваются на процедуры, а повторяющиеся фрагменты оформляются функциями. Кроме того, сам проект, написанный на Perl, может быть разбит на множество файлов и оформлен библиотекой или модулем. Глава «[[{{Root book name}}/Функции и процедуры|Функции и процедуры]]» рассказывает о том, как объявляются пользовательские процедуры и функции. Глава «[[{{Root book name}}/Пакеты, библиотеки и модули|Пакеты, библиотеки и модули]]» рассказывает, как оформить код библиотекой или модулем. Начиная с 5-й версии, в Perl поддерживается ООП парадигма программирования. Она реализована очень необычно, на основе существующих механизмов Perl. Глава «[[{{Root book name}}/Объектно-ориентированное программирование в Perl|Объектно-ориентированное программирование в Perl]]» знакомит читателя, как объявляются классы и реализуется наследование в Perl, а также как строятся объекты и вызываются их методы. В Perl заложен богатый инструментарий для работы со строками. В главе «[[{{Root book name}}/Работа со строками и регулярные выражения|Работа со строками и регулярные выражения]]» рассмотрены регулярные выражения Perl, через которые осуществляется поиск и замена фрагментов в тексте, а также рассмотрены функции, направленные на работу с текстом. Интерпретатор Perl является мультиплатформенным, но и у него есть свои ограничения. Чтобы иметь возможность писать расширяющие модули для любой платформы, разработчики обычно пишут модули на языке Си, в котором используют Perl API, чтобы интегрироваться с интерпретатором. Так как код расширений обычно состоит из функций на языке Си, необходимо писать некоторый склеивающий код, который призван сгладить разницу вызовов внутри Perl API с вызовами в простых программах на языке Си. Для этого обычно используется макроязык Perl XS, который рассмотрен в главе «[[{{Root book name}}/Perl XS|Perl XS]]». Документация к модулям Perl встраивается в их исходные коды, которая может быть извлечена и представлена в удобочитаемой форме. Для языка Perl разработан свой язык документирования, который называется POD ({{lang-en|Plain Old Documentation}}). Язык вместе с подходами документирования исходного кода рассмотрены в главе «[[{{Root book name}}/POD|POD]]». Сообществом программистов Perl разработано множество модулей, которые решают различные задачи. Чтобы разработчики имели возможность обмениваться друг с другом своими наработками, была разработана система CPAN ({{lang-en|Comprehensive Perl Archive Network}} — Всеобъемлющая сеть архивов Perl). В главе «[[{{Root book name}}/CPAN|CPAN]]» рассмотрено как работать с этой системой. В Perl встроена поддержка Юникода и его многобайтная кодировка UTF-8, что позволяет писать интернационализированные приложения. В главе «[[{{Root book name}}/UTF-8|UTF-8]]» рассмотрено как работать с UTF-8 из кода Perl. Всё, что не попало в основное изложение, размещено в «[[{{Root book name}}/Приложения|Приложениях]]» к учебнику. == Запуск программ Perl == [[Файл:Gartoon mimetypes source pl.svg|right|150px]] Для запуска Perl программ вам понадобится интерпретатор <code>perl</code>, который компилирует и запускает программу за один шаг. Запустить программу можно передачей файла с исходным кодом интерпретатору следующим образом: <source lang="bash"> $ perl source_code.pl # Передача аргументов командной оболочки $ perl source_code.pl arg1 arg2 arg3 </source> Используя ключ <code>-e</code>, программу можно передать в момент вызова интерпретатора: <source lang="bash"> $ perl -e 'print "Hello World!\n";' # Примечание: обычно так поступают, когда программа очень короткая, т.н. # программа-однострочник. </source> При запуске программы, внутренний компилятор Perl сначала преобразует исходный код в промежуточное представление (т.н. ''дерево синтаксического анализа''), узлами которого являются коды операций, а далее ядро обработки дерева получает управление и выполняет коды операций в полученном порядке. При обнаружении синтаксической ошибки, интерпретация завершается с кодом 2. В среднем компиляция даже очень большой программы происходит очень быстро и составляет малый процент от времени выполнения. Исключением могут быть только CGI-сценарии, которые могут вызываться сотни и тысячи раз в минуту. Дерево синтаксического анализа не сохраняется между вызовами, поэтому по-сути программа компилируется каждый раз заново, однако, существуют способы сохранить код в некотором сериализованном/скомпилированном двоичном виде, чтобы ускорить или исключить этап компиляции. В *nix системах из кода Perl можно делать интерпретируемые сценарии. Для этого нужно в первой строке исходного файла разместить ''шебанг'' (один из следующих), после которого должен идти код: <source lang="bash"> #!/usr/bin/env perl #!/usr/bin/perl </source> Тогда исходный файл можно сделать исполняемым и запускать без явного вызова интерпретатора: <source lang="bash"> ./source_code.pl </source> Интерпретатор Perl требуется компилировать под конкретную программную архитектуру, но к счастью каждый релиз поставляется уже собранным (в форме дистрибутивного пакета), для разных операционных систем. Скачать интерпретатор можно с официального сайта [https://www.perl.org/get.html www.perl.org]. == Ссылки == * [https://www.perl.org/ Perl.org] * [https://perldoc.perl.org/ Perldoc.perl.org] * [https://www.perlmonks.org/? Perlmonks.org] 3519chgwjvy97ejqvgkjlc9s0inibm1 Викиучебник:GUS2Wiki 4 30040 269871 269832 2026-08-27T01:08:53Z Alexis Jazz 57039 Updating gadget usage statistics from [[Special:GadgetUsage]] ([[phab:T121049]]) 269871 wikitext text/x-wiki {{#ifexist:Project:GUS2Wiki/top|{{/top}}|This page provides a historical record of [[Special:GadgetUsage]] through its page history. To get the data in CSV format, see wikitext. To customize this message or add categories, create [[/top]].}} {|style="width:100%; color:#606000; background-color: #FFFFE0; border:1px solid #EEEE80; padding:2px; margin-bottom:1em" cellpadding=0 |- |<imagemap>Image:Clock and warning.svg|20px rect 100 100 100 100 [[##]] desc none</imagemap> | Следующие данные '''взяты из кеша''', последний раз он обновлялся в '''2026-08-25T09:33:44Z'''. |} {| class="sortable wikitable" ! Гаджет !! data-sort-type="number" | Количество участников !! data-sort-type="number" | Активные участники |- |DotsSyntaxHighlighter || 30 || 1 |- |HotCat || 80 || 0 |- |ImageAnnotator || 25 || 0 |- |contribsrange || 68 || 0 |- |directLinkToCommons || 30 || 0 |- |edittop || data-sort-value="Infinity" | По умолчанию || data-sort-value="Infinity" | По умолчанию |- |exlinks || 99 || 1 |- |extWikiLinksMarker || 18 || 2 |- |histcomb || 156 || 0 |- |markadmins || 52 || 2 |- |markblocked || 41 || 1 |- |popups || 39 || 1 |- |preview || 119 || 1 |- |referenceTooltips || data-sort-value="Infinity" | По умолчанию || data-sort-value="Infinity" | По умолчанию |- |removeAccessKeys || 26 || 0 |- |urldecoder || 32 || 0 |} * [[Служебная:Использование гаджетов]] * [[m:Meta:GUS2Wiki/Script|GUS2Wiki]] <!-- data in CSV format: DotsSyntaxHighlighter,30,1 HotCat,80,0 ImageAnnotator,25,0 contribsrange,68,0 directLinkToCommons,30,0 edittop,default,default exlinks,99,1 extWikiLinksMarker,18,2 histcomb,156,0 markadmins,52,2 markblocked,41,1 popups,39,1 preview,119,1 referenceTooltips,default,default removeAccessKeys,26,0 urldecoder,32,0 --> hwn6zvgbxhfcx89xzmx27hibsw1uha2 Некоторые сведения о Perl 5/Типы данных 0 30386 269873 264286 2026-08-27T06:14:45Z ScriptMaster 15708 /* Скаляры */ 269873 wikitext text/x-wiki {{Навигация учебника}} В языке Perl всего три <u>основных</u> типа данных: * '''Скаляр'''. Предназначен для представления и обработки чисел и последовательностей символов (строк). * '''Массив скаляров'''. Предназначен для хранения и обработки нескольких скалярных данных, доступ к которым осуществляется по индексам. * '''Ассоциативный массив скаляров''' (иногда называемый ''хешем''). Предназначен для создания различных динамических структур: списки, деревья и прочее. Перечисленные типы данных мы рассмотрим в этой главе. Кроме них есть еще и другие типы (например функция может рассматриваться как тип данных), но мы будем рассматривать их в более поздних главах, чтобы не перегружать читателя. == Скаляры == Скаляры позволяют хранить и обрабатывать числовые и строковые литералы. Числовые литералы могут быть записаны в десятичной, восьмеричной и шестнадцатеричной форме. В свою очередь, десятичные числа могут быть записаны в целой или вещественной форме. Вот несколько примеров числовых литералов, которые могут быть присвоены скалярам. <source lang=perl> 25 # Целое число 64.567 # Вещественное число 0.546 # Вещественное число с нулевой целой частью .546 # Несущественные нули допустимо опускать # В языке Perl для больших чисел разряды можно отделять друг от друга символом нижнего подчеркивания # для улучшения читаемости кода. 5465249.682 # Так, следующий числовой литерал может быть записан 5_465_249.682 # Восьмеричные и шестнадцатеричные числа 021 # в десятеричной системе 17. Ведущий ноль указывает на восьмеричную систему счисления # Шестнадцатеричные числа всегда начинаются на префикс "0x", причем использовать "0X" НЕЛЬЗЯ. # Буквы A-F могут быть записаны в любом регистре. 0xAB3 0xf </source> Вещественные числа с плавающей точкой могут быть записаны в экспоненциальной форме: <source lang=perl> # [цифры].[цифры][E|e][+|-][цифры] # <мантисса> E <экспонента> 12.567E12 12.567E+04 1e-85 1E+12 </source> Внутренне Perl использует специальные структуры, чтобы иметь возможность на ходу конвертировать числа в строки и наоборот, а также подбивать точность для хранения чисел, чтобы они занимали место в памяти более компактно. Если число вписывается в диапазон знаковых чисел, что соответствует в языке Си типам <code>long</code> и <code>long long</code> (в зависимости от разрядности архитектуры процессора), оно будет уложено в структуру <code>IV</code> (от ''Integer Value''). Очень большие числа, которые не укладываются в IV, помещаются в беззнаковый тип в структуру <code>UV</code> (от ''Unsigned Value''). Если хранимое число приводит к переполнению беззнакового типа, Perl автоматически конвертирует его в число с плавающей запятой со структурой <code>NV</code> (от ''Numeric Value''), которое внутренне соответствует <code>double</code> или <code>long double</code> или <code>__float128</code> (зависит от того, скомпилирован ли интерпретатор с флагом <code>uselongdouble</code>) в стандарте кодирования IEEE 754. Если системе вывода не хватает точности для представления числа, то используются идентификаторы бесконечности: <code>1.#INF</code> и <code>-1.#INF</code> в Windows и <code>inf</code> или <code>Infinity</code> — в *nix. Строковые литералы должны всегда ограничиваться одинарными (<code>'</code>), двойными (<code>"</code>) или обратными (<code>`</code>) кавычками. В строковых литералах, ограниченных одинарными кавычками, нельзя использовать управляющие последовательности или экранирование, кроме двух: <code>\'</code> (отображает одинарную кавычку) и <code>\\</code> (отображает обратный слеш). Другими словами, одинарные кавычки используются, когда все символы в литерале нужно понимать буквально. Двойные кавычки используются, когда управляющие последовательности должны быть переданы устройству вывода, например для переноса строки или табуляции. Литералы в обратных кавычках используются подобно тому, как это делается в сценариях командных оболочек, т.е. они называют программу, которая должна быть выполнена, а ее вывод должен быть подставлен как большой литерал. Точно такой же способ подстановки вывода есть в командной оболочке Bourne Shell и всех ее производных. <source lang=perl> 'Very long string\n' # Строковый литерал. В нем управляющая последовательность '\n' не будет интерпретироваться "\tVery long string\n" # Две управляющие последовательности будут переданы на устройство вывода, т.е. текст выведется # с отступом и в конце будет перенос на новую строку 'Каталога \'~john/docs\' не существует' # Мы используем одинарные кавычки в литерале, чтобы подчеркнуть путь. 'Диск E:\\ переполнен' # Будет выведено "Диск E:\ переполнен". `ls` # Литералом будет вывод команды ls. </source> Разобравшись в том, что можно хранить в скаляре, рассмотрим как он объявляется. Скаляр, как впрочем и любой другой тип, должен быть присвоен переменной, которая будет отсылать нас на некоторый участок памяти. Присваивание скаляра переменной будет в итоге определять ее тип, как ''переменная, хранящая скаляр''. Для обозначения такой переменной в Perl используется символ доллара <code>$</code>: <source lang=perl> $scalar_variable; $deviceName; $name_1; # Здесь $ означает, что переменная хранит скаляр, а идентификатор за ним означает имя переменной. # В общем случае скаляр может не иметь значения. </source> Скалярная переменная за один раз может хранить либо число, либо строку, причем не существует способа заранее определить что из этого хранится в скаляре. Это связано с тем, что в Perl существует механизм неявного преобразования, который включается когда со скалярами производятся операции. Например, при арифметической операции над двумя скалярами, Perl сначала попытается преобразовать их в числа. Напротив, при строковой конкатенации оба скаляра должны быть преобразованы в строки. Если Perl по какой-то причине не удается преобразовать значение в контексте операции, то интерпретатором будет генерироваться ошибка. <source lang=perl> $price = 15; # Скаляр хранит число print "Книга стоит $price рублей"; # В контексте данной операции число будет преобразовано в строку # Если при подстановке скаляра за именем переменной идут символы, которые можно использовать в именах переменных # (то есть если за подстановкой нет разделителя), нужно поместить имя переменной в фигурные скобки. $day = 15; print "January ${day}th"; # January 15th </source> На практике всегда следует заключать строковые литералы в кавычки, однако это не всегда обязательно. Если интерпретатор Perl обнаружит в программе не закавыченную строку, то он сначала «попытается понять» является ли она ключевым словом Perl. Если слово не является ключевым, то оно будет интерпретировано как строковый литерал. <source lang="perl"> $day = Friday; # Допустимо # Однако, без кавычек можно оставлять строковые литералы, которые имеют только буквы латинского алфавита. </source> == Массивы скаляров == Массив скаляров позволяет представить не один скаляр, а сразу несколько, доступ к которым осуществляется по индексам. Для объявления массива используется пара круглых скобок, называемая ''конструктором массива''. Так как скаляр может хранить числа или строки, то с точки зрения Perl массив может хранить смешанные данные. <source lang="perl"> $day = 15; ("скаляр_1", 156, "скаляр_3", $day) ; </source> При присваивании массива переменной, перед ее именем используется символ <code>@</code>, который указывает, что переменная хранит массив скаляров. Чтобы обратиться к скаляру в массиве, используется синтаксис, подобный обращению к скаляру, но за именем переменной в квадратных скобках указывается индекс. Тем самым, язык подчеркивает, что массив хранит скаляры. Элементы в массиве скаляров отсчитываются с нуля. <source lang="perl"> @array = ("one", 2, "three", 4); print "Element 0: $array[0]\n"; # Печатаем элемент с индексом 0 print "Element 1: ${array[1]}d\n"; # Печатаем элемент с индексом 1 # Допускается использование отрицательных индексов: в этом случае -1 означает последний элемент, # -2 – предпоследний и т.д. print "Element 2: $array[-2]\n"; print "Element 3: $array[-1]\n"; $array[3] = 5; # Изменяем значение с индексом 3 print "Element 3: $array[3]\n"; # Чтобы узнать последний индекс массива, используется такой синтаксис, где # за символом решетки идет имя массива. Такой прием используется для вычисления его размера. print "Last index: $#array\n"; $arr2[0] = 51; # Массив также порождается при добавлении в него хотя бы одного значения print $arr2[0]; </source> Массивы в Perl являются динамическими, т.е. добавление в них новых элементов автоматически увеличивает их размер. Если добавить к массиву элемент, который отстает от последнего элемента на несколько индексов, пустые элементы будут заполняться пустыми строками. В Perl можно обращаться к несуществующим элементам в массиве: в этом случае будет возвращаться пустая строка. В режиме вывода предупреждающих сообщений, при попытке обратиться к несуществующему элементу будет выводиться предупреждение. Как и скаляры, массивы можно распечатать с помощью <code>print</code>. <source lang="perl"> @digits = (1..9); # В данном примере мы сформировали массив через диапазон print "Digits: @digits\n"; # Когда массив подставляется в другой строковый литерал, его элементы будут перечислены через пробел. print "@digits\n"; # Или так. print @digits, "\n"; # Но если оператору он будет передан так, то вывод будет без отделения пробелом. </source> Результат вывода <source lang=""> Digits: 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 123456789 </source> Печать элементов массива аналогична печати скаляров, однако здесь следует упомянуть интересную особенность: <source lang="perl"> $digit = 6; @digit = (5); # В Perl такая ситуация не запрещена. # Что будет здесь напечатано? print "$digit[0]\n" # Правильный ответ будет 5, но в таком случае как нам напечатать скаляр $digit при такой конфигурации строки. # Здесь существует несколько подходов и все они направлены на то, чтобы синтаксис с индексом # представить как строковый литерал. # Следующие три вызова напечатают "6[0]". print "${digit}[0]\n"; print "$digit\[0]\n"; print "$digit" . "[0]\n"; # Оператор . конкатенирует строки </source> Из любого массива можно выделить подмножество (иногда говорят ''получить срез массива''). Для этого нужно использовать такой синтаксис: <source lang="perl"> @digits = (1..15); print "@digits[5,10,14]\n"; # В квадратных скобках через запятую перечисляются индексы элементов, которые мы хотим увидеть в срезе print "@digits[5..10]\n"; # Диапазон индексов print "@digits[1,2,5..9,12,13]\n"; # Смешанный подход </source> Результат <source lang=""> 6 11 15 6 7 8 9 10 11 2 3 6 7 8 9 10 13 14 </source> Если присвоить массив скаляру (т.н. выполнение выражения в скалярном контексте), можно узнать его размер: <source lang="perl"> @arr = (1..5); $size = @arr; print "$size\n"; # Результат: # 5 </source> == Ассоциативные массивы скаляров == Ассоциативные массивы используются в Perl для создания сложных структур, когда возможностей простых массивов не хватает. Концептуально ассоциативные массивы отличаются от простых массивов тем, что в них для ссылки на элементы используются ассоциативные ключи. Ассоциативный ключ является строковым литералом. Далее для краткости мы будем говорить хеш-массив, однако имейте в виду, что оба слова равнозначны. Хеш-массив можно объявить по-разному: <source lang="perl"> # Хеш-массив создается как простой массив, но теперь необходимо в нечетные элементы # помещать ассоциативные ключи, которые будут связываться со значениями, идущими за ними. (key1, value1, key2, value2) ; # Чтобы подчеркнуть то, что в переменной хранится хеш-массив, используется символ '%'. %person = (name, "Larry", surname, "Wall"); # Здесь 'name' ассоциативный ключ к скаляру "Larry", а 'surname' — к "Wall". # Чтобы обратиться к элементу хеш-массива по ключу, используется синтаксис $имя-хеш-массива{"ключ"}. print "Name: $person{name}\nSurname: $person{surname}\n"; # Создание массива через такой конструктор удобен, когда вы преобразуете обычный массив в хеш-массив. # В большинстве случаев следующий способ объявления хеш-массива удобнее. %person = ( name => "Larry", surname => "Wall" ); print "Name: $person{name}\nSurname: $person{surname}\n"; </source> В последнем случае оператор <code>=></code> аналогичен запятой с той разницей, что левый операнд всегда должен быть строковым литералом. Также обратим внимание, что запятую можно поставить в конце и для второго ключа, и это не будет ошибкой <source lang="perl"> %person = ( name => "Larry", surname => "Wall", # запятая здесь не ошибка ); </source> Для добавления нового элемента в хеш-массив или изменения существующего, достаточно просто обратиться по ключу. Если элемента не было, то он будет создан. <source lang="perl"> %person = ( name => "Larry", surname => "Wall" ); print %person, "\n"; $person{name} = "Garry"; # Значение по существующему ключу будет изменено $person{phone} = 1234; # Новое значение будет добавлено print %person, "\n"; delete($person{name}); # Удалить существующий элемент можно с помощью функции delete print %person, "\n"; </source> Для хеш-массивов существуют две встроенные функции, которые позволяют распечатать либо все ключи, либо все значения в массиве. <source lang="perl"> %person = ( name => "Larry", surname => "Wall", phone => 1234, ); print keys(%person), "\n"; # Печатает все ключи хеш-массива print values(%person), "\n"; # Печатает все значения хеш-массива </source> Для хеша тоже можно получить срез, однако, запись этого может немного вас запутать: <source lang="perl"> %fruits = ( apples => 32, bananas => 16, pears => 7, pineapples => 45, oranges => 21 ); print "@fruits{apples, oranges, pears}\n"; # Вывод: # 32 21 7 </source> Обратите внимание, что для получения среза хеша нужно использовать символ <code>@</code>, как в массиве, но индексация по ключам идет через фигурные скобки. == Удаление элементов из массивов == В рамках данной главы мы также рассмотрим способы удаления элементов из массивов, чтобы не возвращаться к этому. Элементы в массивах скаляров и хеш-массивах могут быть удалены несколькими способами, в зависимости от того, что вам нужно в конкретный момент. Если нужно удалить произвольный элемент(ы), можно воспользоваться функцией <code>delete</code>, которой нужно передать элемент по индексу для массивов (или вычисленный срез из элементов), либо указать элемент по ключу — для хешей. Функция <code>delete</code> возвращает значение удаляемого элемента. <source lang="perl"> # Создаем массив из 10 элементов @arr = (1..10); # Примечание: функция scalar заставляет интерпретировать выражение в скалярном контексте. print "Size: " . scalar @arr . "\n@arr\n"; # Удаляем элемент по индексу delete $arr[4]; print "Size: " . scalar @arr . "\n@arr\n"; # Примечание: функция exists возвращает ИСТИНУ, если элемент инициализирован. print STDOUT (exists $arr[4] ? "element exists" : "element doesn't exist") . "\n"; # Удаляем элементы по срезу delete @arr[1,3,6..8]; print "Size: " . scalar @arr . "\n@arr\n"; # Создаем хеш %hash = ( apple => 25, pear => 40, grapes => 100 ); # Примечание: функция keys возвращает массив ключей хеша. print "Hash size (before): " . (scalar keys %hash) . "\n"; # Удаляем элемент внутри хеша delete $hash{pear}; print "Hash size (after): " . (scalar keys %hash) . "\n"; # Следующие конструкции позволяют удалить все элементы из массива и хеша. # Примечание: данный метод удаления не самый оптимальный в плане производительности. delete @arr[0 .. $#arr]; delete @hash{keys %hash}; print "Array size: " . scalar @arr . "\n"; print "Hash size: " . (scalar keys %hash) . "\n"; # Массивы можно удалить быстрее просто обнулив ссылки на них. undef @arr; undef %hash; print "Array completely deleted\n" unless @arr; print "Hash completely deleted\n" unless %hash; </source> Вывод программы будет следующим: <pre> Size: 10 1 2 3 4 5 6 7 8 9 10 Size: 10 1 2 3 4 6 7 8 9 10 element doesn't exist Size: 10 1 3 6 10 Hash size (before): 3 Hash size (after): 2 Array size: 0 Hash size: 0 Array completely deleted Hash completely deleted </pre> Обратите внимание, что если в массиве скаляров остается хотя бы один элемент после удаления, инициированный размер массива уменьшаться никогда не будет. При этом в хэшах удаление элемента ведет к изменению реального размера. Если вам требуется пересчет размера массива, необходимо использовать специальные функции для работы с массивами. Например, если вам требуется добавлять или извлекать элементы массива с его краёв, вы можете использовать функции <code>push</code>, <code>pop</code>, <code>shift</code> и <code>unshift</code>: <source lang="perl"> @arr = (0); # Вставляет элементы из списка в конец массива. push @arr, (1,2,3); print "Size: " . scalar @arr . "\n@arr\n"; # С помощью pop извлекаем элементы в цикле с правого края. while ( defined ($element = pop @arr) ) { print "Poped: $element, Size: " . scalar @arr . "\n@arr\n"; } push @arr, (1..5); print "Size: " . scalar @arr . "\n@arr\n"; # Извлекает крайний левый элемент массива. $element = shift @arr; print "Left element: $element, Size: " . scalar @arr . "\n@arr\n"; # Вставляет элементы из списка в начало массива. unshift @arr, (6,7); print "Size: " . scalar @arr . "\n@arr\n"; </source> Вывод будет таким: <pre> Size: 4 0 1 2 3 Poped: 3, Size: 3 0 1 2 Poped: 2, Size: 2 0 1 Poped: 1, Size: 1 0 Poped: 0, Size: 0 Size: 5 1 2 3 4 5 Left element: 1, Size: 4 2 3 4 5 Size: 6 6 7 2 3 4 5 </pre> Если требуется удаление элементов с произвольной позиции с пересчетом размера, необходимо использовать функцию <code>splice</code>: <source lang="perl"> splice <array>[,<offset>[,<length>[,<list>]]] </source> Данная функция удаляет в массиве <code><array></code> <code><length></code> элементов, начиная со смещения <code><offset></code> и заменяет их элементами из списка <code><list></code>. Все аргументы функции, кроме первого, являются необязательными. Если нет списка <code><list></code>, то элементы будут просто удаляться, а если ничего кроме <code><array></code> не указано — удалено будет всё. <source lang="perl"> @arr = (1..10); print "Size: " . scalar @arr . "\n@arr\n"; # Примечание: # * Обратите внимание, что отсчет смещения начинается с нуля, т.е. смещение 4 # означает 5-й элемент по порядку. # * Функция делает замену из <list> один к одному. # Если размер изменяемых элементов <length> не равен размеру <list>, # функция просто удалит элементы из @arr, которые вышли за предел размера <list>. # Если <length> меньше размера <list>, функция будет использовать размер <list> вместо <length>. # # # Сравните: # Заменит элементы 5, 6, 7 соответственно на 0, 0 и 0. splice @arr, 4, 3, (0, 0, 0); print "Size: " . scalar @arr . "\n@arr\n"; # Размер <length> больше размера <list>, а значит 8-й элемент будет удален. splice @arr, 4, 4, (0, 0, 0); print "Size: " . scalar @arr . "\n@arr\n"; # Размер <length> меньше размера <list>, а значит 7-й элемент будет равен -1. splice @arr, 4, 3, (0, 0, -1); print "Size: " . scalar @arr . "\n@arr\n"; # Удаляем первые 3 элемента splice @arr, 0, 3; print "Size: " . scalar @arr . "\n@arr\n"; </source> Результат: <pre> Size: 10 1 2 3 4 5 6 7 8 9 10 Size: 10 1 2 3 4 0 0 0 8 9 10 Size: 9 1 2 3 4 0 0 0 9 10 Size: 9 1 2 3 4 0 0 -1 9 10 Size: 6 4 0 0 -1 9 10 </pre> == О переменных == Переменная в Perl не может быть рассмотрена вне контекста типов данных и операций, поэтому в этом разделе мы ограничимся только общими словами. * Переменная в Perl, как и в любом языке программирования, это именованный участок памяти. Первый символ перед именем переменной определяет ее тип: <code>$</code> (скаляр), <code>@</code> (массив скаляров), <code>%</code> (хеш-массив). * Имя переменной чувствительно к регистру и может состоять из цифр, букв и символа нижнего подчеркивания и не должно начинаться с цифры, а также не должно совпадать с зарезервированным в Perl словом. В Perl может быть создано три одноименных переменных, каждая из которых хранит по отдельному типу данных, например <code>$var</code>, <code>@var</code> и <code>%var</code>. Это возможно потому, что интерпретатор хранит имена переменных в разных списках для разных типов внутри таблицы символов пакета (о чём будет рассказано в поздних главах). * В выражениях, когда в качестве операнда используется некоторый тип, его интерпретация может зависеть от контекста, в котором он вычисляется, в частности существует два контекста: ''скалярный'' и ''списковый'' (''векторный''). Это важно, так как от этого будет зависеть конечный результат выражения. Об этом будет подробно рассказано, когда речь пойдет об операциях. * Любая переменная может находиться в состоянии определена или не определена. Переменная считается определенной, если ей присвоено какое-то значение. Чтобы определить статус переменной, следует пользоваться встроенной функцией <code>defined</code>.<source lang="perl"> print "not defined\n" if ! defined $arg; $arg = 1; print "defined\n" if defined $arg; $arg = undef; print "not defined\n" if ! defined $arg; # Результат: # not defined # defined # not defined </source> * Переменную можно сделать неопределенной, если вызвать функцию <code>undef</code>. Вызов этой функции будет приводить к освобождению памяти от ненужных данных. * Любая переменная имеет некоторую видимость относительно других участков программы. Видимость зависит от того, где и как переменная объявлена. Например, в вышеприведенных примерах все переменные были объявлены в глобальной области видимости. Когда переменная выходит из своей области видимости, она уничтожается. 7c8ik771u34g311zpziarqysy0aeb3t 269874 269873 2026-08-27T07:16:22Z ScriptMaster 15708 /* Скаляры */ 269874 wikitext text/x-wiki {{Навигация учебника}} В языке Perl всего три <u>основных</u> типа данных: * '''Скаляр'''. Предназначен для представления и обработки чисел и последовательностей символов (строк). * '''Массив скаляров'''. Предназначен для хранения и обработки нескольких скалярных данных, доступ к которым осуществляется по индексам. * '''Ассоциативный массив скаляров''' (иногда называемый ''хешем''). Предназначен для создания различных динамических структур: списки, деревья и прочее. Перечисленные типы данных мы рассмотрим в этой главе. Кроме них есть еще и другие типы (например функция может рассматриваться как тип данных), но мы будем рассматривать их в более поздних главах, чтобы не перегружать читателя. == Скаляры == Скаляры позволяют хранить и обрабатывать числовые и строковые литералы. Числовые литералы могут быть записаны в десятичной, восьмеричной и шестнадцатеричной форме. В свою очередь, десятичные числа могут быть записаны в целой или вещественной форме. Вот несколько примеров числовых литералов, которые могут быть присвоены скалярам. <source lang=perl> 25 # Целое число 64.567 # Вещественное число 0.546 # Вещественное число с нулевой целой частью .546 # Несущественные нули допустимо опускать # В языке Perl для больших чисел разряды можно отделять друг от друга символом нижнего подчеркивания # для улучшения читаемости кода. 5465249.682 # Так, следующий числовой литерал может быть записан 5_465_249.682 # Восьмеричные и шестнадцатеричные числа 021 # в десятеричной системе 17. Ведущий ноль указывает на восьмеричную систему счисления # Шестнадцатеричные числа всегда начинаются на префикс "0x", причем использовать "0X" НЕЛЬЗЯ. # Буквы A-F могут быть записаны в любом регистре. 0xAB3 0xf </source> Вещественные числа с плавающей точкой могут быть записаны в экспоненциальной форме: <source lang=perl> # [цифры].[цифры][E|e][+|-][цифры] # <мантисса> E <экспонента> 12.567E12 12.567E+04 1e-85 1E+12 </source> Внутренне Perl использует специальные структуры, чтобы иметь возможность на ходу конвертировать числа в строки и наоборот, а также подбивать точность для хранения чисел, чтобы они занимали место в памяти более компактно. Если число вписывается в диапазон знаковых чисел, что соответствует в языке Си типам <code>long</code> и <code>long long</code> (в зависимости от разрядности архитектуры процессора), оно будет уложено в структуру <code>IV</code> (от ''Integer Value''). Очень большие числа, которые не укладываются в IV, помещаются в беззнаковый тип в структуру <code>UV</code> (от ''Unsigned Value''). Если хранимое число приводит к переполнению беззнакового типа, Perl автоматически конвертирует его в число с плавающей запятой со структурой <code>NV</code> (от ''Numeric Value''), которое внутренне соответствует <code>double</code> или <code>long double</code> или <code>__float128</code> (зависит от того, скомпилирован ли интерпретатор с флагом <code>uselongdouble</code>) в стандарте кодирования IEEE 754. Если системе вывода не хватает точности для представления числа, то используются идентификаторы бесконечности: <code>1.#INF</code> и <code>-1.#INF</code> в Windows и <code>inf</code> или <code>Infinity</code> — в *nix. Строковые литералы должны всегда ограничиваться одинарными (<code>'</code>), двойными (<code>"</code>) или обратными (<code>`</code>) кавычками. В строковых литералах, ограниченных одинарными кавычками, нельзя использовать управляющие последовательности или экранирование, кроме двух: <code>\'</code> (отображает одинарную кавычку) и <code>\\</code> (отображает обратный слеш). Другими словами, одинарные кавычки используются, когда все символы в литерале нужно понимать буквально. Двойные кавычки используются, когда управляющие последовательности должны быть переданы устройству вывода, например для переноса строки или табуляции. Литералы в обратных кавычках используются подобно тому, как это делается в сценариях командных оболочек, т.е. они называют программу, которая должна быть выполнена, а ее вывод должен быть подставлен как большой литерал. Точно такой же способ подстановки вывода есть в командной оболочке Bourne Shell и всех ее производных. <source lang=perl> 'Very long string\n' # Строковый литерал. В нем управляющая последовательность '\n' не будет интерпретироваться "\tVery long string\n" # Две управляющие последовательности будут переданы на устройство вывода, т.е. текст выведется # с отступом и в конце будет перенос на новую строку 'Каталога \'~john/docs\' не существует' # Мы используем одинарные кавычки в литерале, чтобы подчеркнуть путь. 'Диск E:\\ переполнен' # Будет выведено "Диск E:\ переполнен". `ls` # Литералом будет вывод команды ls. </source> Разобравшись в том, что можно хранить в скаляре, рассмотрим как он объявляется. Скаляр, как впрочем и любой другой тип, должен быть присвоен переменной, которая будет отсылать нас на некоторый участок памяти. Присваивание скаляра переменной будет в итоге определять ее тип, как ''переменная, хранящая скаляр''. Для обозначения такой переменной в Perl используется символ доллара <code>$</code><ref>Первый символ любой переменной кодирует тип данных, который будет в ней хранится, и в сообществе Perl называется ''сигилом'', тем самым иносказательно намекая, что это слово языка Perl в семантическом смысле. Литералы с сигилом во многих операциях являются вычисляемыми единицами. Например в унарной операции <code>print</code> все подстроки с сигилами будут сначала вычислены (''evaluable line''). Однако, в этой книги мы не будем использовать термин сигил, предпочитая более привычный ''идентификатор типа''.</ref>: <source lang=perl> $scalar_variable; $deviceName; $name_1; # Здесь $ означает, что переменная хранит скаляр, а идентификатор за ним означает имя переменной. # В общем случае скаляр может не иметь значения. </source> Скалярная переменная за один раз может хранить либо число, либо строку, причем не существует способа заранее определить что из этого хранится в скаляре. Это связано с тем, что в Perl существует механизм неявного преобразования, который включается когда со скалярами производятся операции. Например, при арифметической операции над двумя скалярами, Perl сначала попытается преобразовать их в числа. Напротив, при строковой конкатенации оба скаляра должны быть преобразованы в строки. Если Perl по какой-то причине не удается преобразовать значение в контексте операции, то интерпретатором будет генерироваться ошибка. <source lang=perl> $price = 15; # Скаляр хранит число print "Книга стоит $price рублей"; # В контексте данной операции число будет преобразовано в строку # Если при подстановке скаляра за именем переменной идут символы, которые можно использовать в именах переменных # (то есть если за подстановкой нет разделителя), нужно поместить имя переменной в фигурные скобки. $day = 15; print "January ${day}th"; # January 15th </source> На практике всегда следует заключать строковые литералы в кавычки, однако это не всегда обязательно. Если интерпретатор Perl обнаружит в программе не закавыченную строку, то он сначала «попытается понять» является ли она ключевым словом Perl. Если слово не является ключевым, то оно будет интерпретировано как строковый литерал. <source lang="perl"> $day = Friday; # Допустимо # Однако, без кавычек можно оставлять строковые литералы, которые имеют только буквы латинского алфавита. </source> == Массивы скаляров == Массив скаляров позволяет представить не один скаляр, а сразу несколько, доступ к которым осуществляется по индексам. Для объявления массива используется пара круглых скобок, называемая ''конструктором массива''. Так как скаляр может хранить числа или строки, то с точки зрения Perl массив может хранить смешанные данные. <source lang="perl"> $day = 15; ("скаляр_1", 156, "скаляр_3", $day) ; </source> При присваивании массива переменной, перед ее именем используется символ <code>@</code>, который указывает, что переменная хранит массив скаляров. Чтобы обратиться к скаляру в массиве, используется синтаксис, подобный обращению к скаляру, но за именем переменной в квадратных скобках указывается индекс. Тем самым, язык подчеркивает, что массив хранит скаляры. Элементы в массиве скаляров отсчитываются с нуля. <source lang="perl"> @array = ("one", 2, "three", 4); print "Element 0: $array[0]\n"; # Печатаем элемент с индексом 0 print "Element 1: ${array[1]}d\n"; # Печатаем элемент с индексом 1 # Допускается использование отрицательных индексов: в этом случае -1 означает последний элемент, # -2 – предпоследний и т.д. print "Element 2: $array[-2]\n"; print "Element 3: $array[-1]\n"; $array[3] = 5; # Изменяем значение с индексом 3 print "Element 3: $array[3]\n"; # Чтобы узнать последний индекс массива, используется такой синтаксис, где # за символом решетки идет имя массива. Такой прием используется для вычисления его размера. print "Last index: $#array\n"; $arr2[0] = 51; # Массив также порождается при добавлении в него хотя бы одного значения print $arr2[0]; </source> Массивы в Perl являются динамическими, т.е. добавление в них новых элементов автоматически увеличивает их размер. Если добавить к массиву элемент, который отстает от последнего элемента на несколько индексов, пустые элементы будут заполняться пустыми строками. В Perl можно обращаться к несуществующим элементам в массиве: в этом случае будет возвращаться пустая строка. В режиме вывода предупреждающих сообщений, при попытке обратиться к несуществующему элементу будет выводиться предупреждение. Как и скаляры, массивы можно распечатать с помощью <code>print</code>. <source lang="perl"> @digits = (1..9); # В данном примере мы сформировали массив через диапазон print "Digits: @digits\n"; # Когда массив подставляется в другой строковый литерал, его элементы будут перечислены через пробел. print "@digits\n"; # Или так. print @digits, "\n"; # Но если оператору он будет передан так, то вывод будет без отделения пробелом. </source> Результат вывода <source lang=""> Digits: 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 123456789 </source> Печать элементов массива аналогична печати скаляров, однако здесь следует упомянуть интересную особенность: <source lang="perl"> $digit = 6; @digit = (5); # В Perl такая ситуация не запрещена. # Что будет здесь напечатано? print "$digit[0]\n" # Правильный ответ будет 5, но в таком случае как нам напечатать скаляр $digit при такой конфигурации строки. # Здесь существует несколько подходов и все они направлены на то, чтобы синтаксис с индексом # представить как строковый литерал. # Следующие три вызова напечатают "6[0]". print "${digit}[0]\n"; print "$digit\[0]\n"; print "$digit" . "[0]\n"; # Оператор . конкатенирует строки </source> Из любого массива можно выделить подмножество (иногда говорят ''получить срез массива''). Для этого нужно использовать такой синтаксис: <source lang="perl"> @digits = (1..15); print "@digits[5,10,14]\n"; # В квадратных скобках через запятую перечисляются индексы элементов, которые мы хотим увидеть в срезе print "@digits[5..10]\n"; # Диапазон индексов print "@digits[1,2,5..9,12,13]\n"; # Смешанный подход </source> Результат <source lang=""> 6 11 15 6 7 8 9 10 11 2 3 6 7 8 9 10 13 14 </source> Если присвоить массив скаляру (т.н. выполнение выражения в скалярном контексте), можно узнать его размер: <source lang="perl"> @arr = (1..5); $size = @arr; print "$size\n"; # Результат: # 5 </source> == Ассоциативные массивы скаляров == Ассоциативные массивы используются в Perl для создания сложных структур, когда возможностей простых массивов не хватает. Концептуально ассоциативные массивы отличаются от простых массивов тем, что в них для ссылки на элементы используются ассоциативные ключи. Ассоциативный ключ является строковым литералом. Далее для краткости мы будем говорить хеш-массив, однако имейте в виду, что оба слова равнозначны. Хеш-массив можно объявить по-разному: <source lang="perl"> # Хеш-массив создается как простой массив, но теперь необходимо в нечетные элементы # помещать ассоциативные ключи, которые будут связываться со значениями, идущими за ними. (key1, value1, key2, value2) ; # Чтобы подчеркнуть то, что в переменной хранится хеш-массив, используется символ '%'. %person = (name, "Larry", surname, "Wall"); # Здесь 'name' ассоциативный ключ к скаляру "Larry", а 'surname' — к "Wall". # Чтобы обратиться к элементу хеш-массива по ключу, используется синтаксис $имя-хеш-массива{"ключ"}. print "Name: $person{name}\nSurname: $person{surname}\n"; # Создание массива через такой конструктор удобен, когда вы преобразуете обычный массив в хеш-массив. # В большинстве случаев следующий способ объявления хеш-массива удобнее. %person = ( name => "Larry", surname => "Wall" ); print "Name: $person{name}\nSurname: $person{surname}\n"; </source> В последнем случае оператор <code>=></code> аналогичен запятой с той разницей, что левый операнд всегда должен быть строковым литералом. Также обратим внимание, что запятую можно поставить в конце и для второго ключа, и это не будет ошибкой <source lang="perl"> %person = ( name => "Larry", surname => "Wall", # запятая здесь не ошибка ); </source> Для добавления нового элемента в хеш-массив или изменения существующего, достаточно просто обратиться по ключу. Если элемента не было, то он будет создан. <source lang="perl"> %person = ( name => "Larry", surname => "Wall" ); print %person, "\n"; $person{name} = "Garry"; # Значение по существующему ключу будет изменено $person{phone} = 1234; # Новое значение будет добавлено print %person, "\n"; delete($person{name}); # Удалить существующий элемент можно с помощью функции delete print %person, "\n"; </source> Для хеш-массивов существуют две встроенные функции, которые позволяют распечатать либо все ключи, либо все значения в массиве. <source lang="perl"> %person = ( name => "Larry", surname => "Wall", phone => 1234, ); print keys(%person), "\n"; # Печатает все ключи хеш-массива print values(%person), "\n"; # Печатает все значения хеш-массива </source> Для хеша тоже можно получить срез, однако, запись этого может немного вас запутать: <source lang="perl"> %fruits = ( apples => 32, bananas => 16, pears => 7, pineapples => 45, oranges => 21 ); print "@fruits{apples, oranges, pears}\n"; # Вывод: # 32 21 7 </source> Обратите внимание, что для получения среза хеша нужно использовать символ <code>@</code>, как в массиве, но индексация по ключам идет через фигурные скобки. == Удаление элементов из массивов == В рамках данной главы мы также рассмотрим способы удаления элементов из массивов, чтобы не возвращаться к этому. Элементы в массивах скаляров и хеш-массивах могут быть удалены несколькими способами, в зависимости от того, что вам нужно в конкретный момент. Если нужно удалить произвольный элемент(ы), можно воспользоваться функцией <code>delete</code>, которой нужно передать элемент по индексу для массивов (или вычисленный срез из элементов), либо указать элемент по ключу — для хешей. Функция <code>delete</code> возвращает значение удаляемого элемента. <source lang="perl"> # Создаем массив из 10 элементов @arr = (1..10); # Примечание: функция scalar заставляет интерпретировать выражение в скалярном контексте. print "Size: " . scalar @arr . "\n@arr\n"; # Удаляем элемент по индексу delete $arr[4]; print "Size: " . scalar @arr . "\n@arr\n"; # Примечание: функция exists возвращает ИСТИНУ, если элемент инициализирован. print STDOUT (exists $arr[4] ? "element exists" : "element doesn't exist") . "\n"; # Удаляем элементы по срезу delete @arr[1,3,6..8]; print "Size: " . scalar @arr . "\n@arr\n"; # Создаем хеш %hash = ( apple => 25, pear => 40, grapes => 100 ); # Примечание: функция keys возвращает массив ключей хеша. print "Hash size (before): " . (scalar keys %hash) . "\n"; # Удаляем элемент внутри хеша delete $hash{pear}; print "Hash size (after): " . (scalar keys %hash) . "\n"; # Следующие конструкции позволяют удалить все элементы из массива и хеша. # Примечание: данный метод удаления не самый оптимальный в плане производительности. delete @arr[0 .. $#arr]; delete @hash{keys %hash}; print "Array size: " . scalar @arr . "\n"; print "Hash size: " . (scalar keys %hash) . "\n"; # Массивы можно удалить быстрее просто обнулив ссылки на них. undef @arr; undef %hash; print "Array completely deleted\n" unless @arr; print "Hash completely deleted\n" unless %hash; </source> Вывод программы будет следующим: <pre> Size: 10 1 2 3 4 5 6 7 8 9 10 Size: 10 1 2 3 4 6 7 8 9 10 element doesn't exist Size: 10 1 3 6 10 Hash size (before): 3 Hash size (after): 2 Array size: 0 Hash size: 0 Array completely deleted Hash completely deleted </pre> Обратите внимание, что если в массиве скаляров остается хотя бы один элемент после удаления, инициированный размер массива уменьшаться никогда не будет. При этом в хэшах удаление элемента ведет к изменению реального размера. Если вам требуется пересчет размера массива, необходимо использовать специальные функции для работы с массивами. Например, если вам требуется добавлять или извлекать элементы массива с его краёв, вы можете использовать функции <code>push</code>, <code>pop</code>, <code>shift</code> и <code>unshift</code>: <source lang="perl"> @arr = (0); # Вставляет элементы из списка в конец массива. push @arr, (1,2,3); print "Size: " . scalar @arr . "\n@arr\n"; # С помощью pop извлекаем элементы в цикле с правого края. while ( defined ($element = pop @arr) ) { print "Poped: $element, Size: " . scalar @arr . "\n@arr\n"; } push @arr, (1..5); print "Size: " . scalar @arr . "\n@arr\n"; # Извлекает крайний левый элемент массива. $element = shift @arr; print "Left element: $element, Size: " . scalar @arr . "\n@arr\n"; # Вставляет элементы из списка в начало массива. unshift @arr, (6,7); print "Size: " . scalar @arr . "\n@arr\n"; </source> Вывод будет таким: <pre> Size: 4 0 1 2 3 Poped: 3, Size: 3 0 1 2 Poped: 2, Size: 2 0 1 Poped: 1, Size: 1 0 Poped: 0, Size: 0 Size: 5 1 2 3 4 5 Left element: 1, Size: 4 2 3 4 5 Size: 6 6 7 2 3 4 5 </pre> Если требуется удаление элементов с произвольной позиции с пересчетом размера, необходимо использовать функцию <code>splice</code>: <source lang="perl"> splice <array>[,<offset>[,<length>[,<list>]]] </source> Данная функция удаляет в массиве <code><array></code> <code><length></code> элементов, начиная со смещения <code><offset></code> и заменяет их элементами из списка <code><list></code>. Все аргументы функции, кроме первого, являются необязательными. Если нет списка <code><list></code>, то элементы будут просто удаляться, а если ничего кроме <code><array></code> не указано — удалено будет всё. <source lang="perl"> @arr = (1..10); print "Size: " . scalar @arr . "\n@arr\n"; # Примечание: # * Обратите внимание, что отсчет смещения начинается с нуля, т.е. смещение 4 # означает 5-й элемент по порядку. # * Функция делает замену из <list> один к одному. # Если размер изменяемых элементов <length> не равен размеру <list>, # функция просто удалит элементы из @arr, которые вышли за предел размера <list>. # Если <length> меньше размера <list>, функция будет использовать размер <list> вместо <length>. # # # Сравните: # Заменит элементы 5, 6, 7 соответственно на 0, 0 и 0. splice @arr, 4, 3, (0, 0, 0); print "Size: " . scalar @arr . "\n@arr\n"; # Размер <length> больше размера <list>, а значит 8-й элемент будет удален. splice @arr, 4, 4, (0, 0, 0); print "Size: " . scalar @arr . "\n@arr\n"; # Размер <length> меньше размера <list>, а значит 7-й элемент будет равен -1. splice @arr, 4, 3, (0, 0, -1); print "Size: " . scalar @arr . "\n@arr\n"; # Удаляем первые 3 элемента splice @arr, 0, 3; print "Size: " . scalar @arr . "\n@arr\n"; </source> Результат: <pre> Size: 10 1 2 3 4 5 6 7 8 9 10 Size: 10 1 2 3 4 0 0 0 8 9 10 Size: 9 1 2 3 4 0 0 0 9 10 Size: 9 1 2 3 4 0 0 -1 9 10 Size: 6 4 0 0 -1 9 10 </pre> == О переменных == Переменная в Perl не может быть рассмотрена вне контекста типов данных и операций, поэтому в этом разделе мы ограничимся только общими словами. * Переменная в Perl, как и в любом языке программирования, это именованный участок памяти. Первый символ перед именем переменной определяет ее тип: <code>$</code> (скаляр), <code>@</code> (массив скаляров), <code>%</code> (хеш-массив). * Имя переменной чувствительно к регистру и может состоять из цифр, букв и символа нижнего подчеркивания и не должно начинаться с цифры, а также не должно совпадать с зарезервированным в Perl словом. В Perl может быть создано три одноименных переменных, каждая из которых хранит по отдельному типу данных, например <code>$var</code>, <code>@var</code> и <code>%var</code>. Это возможно потому, что интерпретатор хранит имена переменных в разных списках для разных типов внутри таблицы символов пакета (о чём будет рассказано в поздних главах). * В выражениях, когда в качестве операнда используется некоторый тип, его интерпретация может зависеть от контекста, в котором он вычисляется, в частности существует два контекста: ''скалярный'' и ''списковый'' (''векторный''). Это важно, так как от этого будет зависеть конечный результат выражения. Об этом будет подробно рассказано, когда речь пойдет об операциях. * Любая переменная может находиться в состоянии определена или не определена. Переменная считается определенной, если ей присвоено какое-то значение. Чтобы определить статус переменной, следует пользоваться встроенной функцией <code>defined</code>.<source lang="perl"> print "not defined\n" if ! defined $arg; $arg = 1; print "defined\n" if defined $arg; $arg = undef; print "not defined\n" if ! defined $arg; # Результат: # not defined # defined # not defined </source> * Переменную можно сделать неопределенной, если вызвать функцию <code>undef</code>. Вызов этой функции будет приводить к освобождению памяти от ненужных данных. * Любая переменная имеет некоторую видимость относительно других участков программы. Видимость зависит от того, где и как переменная объявлена. Например, в вышеприведенных примерах все переменные были объявлены в глобальной области видимости. Когда переменная выходит из своей области видимости, она уничтожается. 41qaillbfjwomf1z2bh1o3u9vc3p3ii 269875 269874 2026-08-27T07:17:06Z ScriptMaster 15708 /* О переменных */ 269875 wikitext text/x-wiki {{Навигация учебника}} В языке Perl всего три <u>основных</u> типа данных: * '''Скаляр'''. Предназначен для представления и обработки чисел и последовательностей символов (строк). * '''Массив скаляров'''. Предназначен для хранения и обработки нескольких скалярных данных, доступ к которым осуществляется по индексам. * '''Ассоциативный массив скаляров''' (иногда называемый ''хешем''). Предназначен для создания различных динамических структур: списки, деревья и прочее. Перечисленные типы данных мы рассмотрим в этой главе. Кроме них есть еще и другие типы (например функция может рассматриваться как тип данных), но мы будем рассматривать их в более поздних главах, чтобы не перегружать читателя. == Скаляры == Скаляры позволяют хранить и обрабатывать числовые и строковые литералы. Числовые литералы могут быть записаны в десятичной, восьмеричной и шестнадцатеричной форме. В свою очередь, десятичные числа могут быть записаны в целой или вещественной форме. Вот несколько примеров числовых литералов, которые могут быть присвоены скалярам. <source lang=perl> 25 # Целое число 64.567 # Вещественное число 0.546 # Вещественное число с нулевой целой частью .546 # Несущественные нули допустимо опускать # В языке Perl для больших чисел разряды можно отделять друг от друга символом нижнего подчеркивания # для улучшения читаемости кода. 5465249.682 # Так, следующий числовой литерал может быть записан 5_465_249.682 # Восьмеричные и шестнадцатеричные числа 021 # в десятеричной системе 17. Ведущий ноль указывает на восьмеричную систему счисления # Шестнадцатеричные числа всегда начинаются на префикс "0x", причем использовать "0X" НЕЛЬЗЯ. # Буквы A-F могут быть записаны в любом регистре. 0xAB3 0xf </source> Вещественные числа с плавающей точкой могут быть записаны в экспоненциальной форме: <source lang=perl> # [цифры].[цифры][E|e][+|-][цифры] # <мантисса> E <экспонента> 12.567E12 12.567E+04 1e-85 1E+12 </source> Внутренне Perl использует специальные структуры, чтобы иметь возможность на ходу конвертировать числа в строки и наоборот, а также подбивать точность для хранения чисел, чтобы они занимали место в памяти более компактно. Если число вписывается в диапазон знаковых чисел, что соответствует в языке Си типам <code>long</code> и <code>long long</code> (в зависимости от разрядности архитектуры процессора), оно будет уложено в структуру <code>IV</code> (от ''Integer Value''). Очень большие числа, которые не укладываются в IV, помещаются в беззнаковый тип в структуру <code>UV</code> (от ''Unsigned Value''). Если хранимое число приводит к переполнению беззнакового типа, Perl автоматически конвертирует его в число с плавающей запятой со структурой <code>NV</code> (от ''Numeric Value''), которое внутренне соответствует <code>double</code> или <code>long double</code> или <code>__float128</code> (зависит от того, скомпилирован ли интерпретатор с флагом <code>uselongdouble</code>) в стандарте кодирования IEEE 754. Если системе вывода не хватает точности для представления числа, то используются идентификаторы бесконечности: <code>1.#INF</code> и <code>-1.#INF</code> в Windows и <code>inf</code> или <code>Infinity</code> — в *nix. Строковые литералы должны всегда ограничиваться одинарными (<code>'</code>), двойными (<code>"</code>) или обратными (<code>`</code>) кавычками. В строковых литералах, ограниченных одинарными кавычками, нельзя использовать управляющие последовательности или экранирование, кроме двух: <code>\'</code> (отображает одинарную кавычку) и <code>\\</code> (отображает обратный слеш). Другими словами, одинарные кавычки используются, когда все символы в литерале нужно понимать буквально. Двойные кавычки используются, когда управляющие последовательности должны быть переданы устройству вывода, например для переноса строки или табуляции. Литералы в обратных кавычках используются подобно тому, как это делается в сценариях командных оболочек, т.е. они называют программу, которая должна быть выполнена, а ее вывод должен быть подставлен как большой литерал. Точно такой же способ подстановки вывода есть в командной оболочке Bourne Shell и всех ее производных. <source lang=perl> 'Very long string\n' # Строковый литерал. В нем управляющая последовательность '\n' не будет интерпретироваться "\tVery long string\n" # Две управляющие последовательности будут переданы на устройство вывода, т.е. текст выведется # с отступом и в конце будет перенос на новую строку 'Каталога \'~john/docs\' не существует' # Мы используем одинарные кавычки в литерале, чтобы подчеркнуть путь. 'Диск E:\\ переполнен' # Будет выведено "Диск E:\ переполнен". `ls` # Литералом будет вывод команды ls. </source> Разобравшись в том, что можно хранить в скаляре, рассмотрим как он объявляется. Скаляр, как впрочем и любой другой тип, должен быть присвоен переменной, которая будет отсылать нас на некоторый участок памяти. Присваивание скаляра переменной будет в итоге определять ее тип, как ''переменная, хранящая скаляр''. Для обозначения такой переменной в Perl используется символ доллара <code>$</code><ref>Первый символ любой переменной кодирует тип данных, который будет в ней хранится, и в сообществе Perl называется ''сигилом'', тем самым иносказательно намекая, что это слово языка Perl в семантическом смысле. Литералы с сигилом во многих операциях являются вычисляемыми единицами. Например в унарной операции <code>print</code> все подстроки с сигилами будут сначала вычислены (''evaluable line''). Однако, в этой книги мы не будем использовать термин сигил, предпочитая более привычный ''идентификатор типа''.</ref>: <source lang=perl> $scalar_variable; $deviceName; $name_1; # Здесь $ означает, что переменная хранит скаляр, а идентификатор за ним означает имя переменной. # В общем случае скаляр может не иметь значения. </source> Скалярная переменная за один раз может хранить либо число, либо строку, причем не существует способа заранее определить что из этого хранится в скаляре. Это связано с тем, что в Perl существует механизм неявного преобразования, который включается когда со скалярами производятся операции. Например, при арифметической операции над двумя скалярами, Perl сначала попытается преобразовать их в числа. Напротив, при строковой конкатенации оба скаляра должны быть преобразованы в строки. Если Perl по какой-то причине не удается преобразовать значение в контексте операции, то интерпретатором будет генерироваться ошибка. <source lang=perl> $price = 15; # Скаляр хранит число print "Книга стоит $price рублей"; # В контексте данной операции число будет преобразовано в строку # Если при подстановке скаляра за именем переменной идут символы, которые можно использовать в именах переменных # (то есть если за подстановкой нет разделителя), нужно поместить имя переменной в фигурные скобки. $day = 15; print "January ${day}th"; # January 15th </source> На практике всегда следует заключать строковые литералы в кавычки, однако это не всегда обязательно. Если интерпретатор Perl обнаружит в программе не закавыченную строку, то он сначала «попытается понять» является ли она ключевым словом Perl. Если слово не является ключевым, то оно будет интерпретировано как строковый литерал. <source lang="perl"> $day = Friday; # Допустимо # Однако, без кавычек можно оставлять строковые литералы, которые имеют только буквы латинского алфавита. </source> == Массивы скаляров == Массив скаляров позволяет представить не один скаляр, а сразу несколько, доступ к которым осуществляется по индексам. Для объявления массива используется пара круглых скобок, называемая ''конструктором массива''. Так как скаляр может хранить числа или строки, то с точки зрения Perl массив может хранить смешанные данные. <source lang="perl"> $day = 15; ("скаляр_1", 156, "скаляр_3", $day) ; </source> При присваивании массива переменной, перед ее именем используется символ <code>@</code>, который указывает, что переменная хранит массив скаляров. Чтобы обратиться к скаляру в массиве, используется синтаксис, подобный обращению к скаляру, но за именем переменной в квадратных скобках указывается индекс. Тем самым, язык подчеркивает, что массив хранит скаляры. Элементы в массиве скаляров отсчитываются с нуля. <source lang="perl"> @array = ("one", 2, "three", 4); print "Element 0: $array[0]\n"; # Печатаем элемент с индексом 0 print "Element 1: ${array[1]}d\n"; # Печатаем элемент с индексом 1 # Допускается использование отрицательных индексов: в этом случае -1 означает последний элемент, # -2 – предпоследний и т.д. print "Element 2: $array[-2]\n"; print "Element 3: $array[-1]\n"; $array[3] = 5; # Изменяем значение с индексом 3 print "Element 3: $array[3]\n"; # Чтобы узнать последний индекс массива, используется такой синтаксис, где # за символом решетки идет имя массива. Такой прием используется для вычисления его размера. print "Last index: $#array\n"; $arr2[0] = 51; # Массив также порождается при добавлении в него хотя бы одного значения print $arr2[0]; </source> Массивы в Perl являются динамическими, т.е. добавление в них новых элементов автоматически увеличивает их размер. Если добавить к массиву элемент, который отстает от последнего элемента на несколько индексов, пустые элементы будут заполняться пустыми строками. В Perl можно обращаться к несуществующим элементам в массиве: в этом случае будет возвращаться пустая строка. В режиме вывода предупреждающих сообщений, при попытке обратиться к несуществующему элементу будет выводиться предупреждение. Как и скаляры, массивы можно распечатать с помощью <code>print</code>. <source lang="perl"> @digits = (1..9); # В данном примере мы сформировали массив через диапазон print "Digits: @digits\n"; # Когда массив подставляется в другой строковый литерал, его элементы будут перечислены через пробел. print "@digits\n"; # Или так. print @digits, "\n"; # Но если оператору он будет передан так, то вывод будет без отделения пробелом. </source> Результат вывода <source lang=""> Digits: 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 123456789 </source> Печать элементов массива аналогична печати скаляров, однако здесь следует упомянуть интересную особенность: <source lang="perl"> $digit = 6; @digit = (5); # В Perl такая ситуация не запрещена. # Что будет здесь напечатано? print "$digit[0]\n" # Правильный ответ будет 5, но в таком случае как нам напечатать скаляр $digit при такой конфигурации строки. # Здесь существует несколько подходов и все они направлены на то, чтобы синтаксис с индексом # представить как строковый литерал. # Следующие три вызова напечатают "6[0]". print "${digit}[0]\n"; print "$digit\[0]\n"; print "$digit" . "[0]\n"; # Оператор . конкатенирует строки </source> Из любого массива можно выделить подмножество (иногда говорят ''получить срез массива''). Для этого нужно использовать такой синтаксис: <source lang="perl"> @digits = (1..15); print "@digits[5,10,14]\n"; # В квадратных скобках через запятую перечисляются индексы элементов, которые мы хотим увидеть в срезе print "@digits[5..10]\n"; # Диапазон индексов print "@digits[1,2,5..9,12,13]\n"; # Смешанный подход </source> Результат <source lang=""> 6 11 15 6 7 8 9 10 11 2 3 6 7 8 9 10 13 14 </source> Если присвоить массив скаляру (т.н. выполнение выражения в скалярном контексте), можно узнать его размер: <source lang="perl"> @arr = (1..5); $size = @arr; print "$size\n"; # Результат: # 5 </source> == Ассоциативные массивы скаляров == Ассоциативные массивы используются в Perl для создания сложных структур, когда возможностей простых массивов не хватает. Концептуально ассоциативные массивы отличаются от простых массивов тем, что в них для ссылки на элементы используются ассоциативные ключи. Ассоциативный ключ является строковым литералом. Далее для краткости мы будем говорить хеш-массив, однако имейте в виду, что оба слова равнозначны. Хеш-массив можно объявить по-разному: <source lang="perl"> # Хеш-массив создается как простой массив, но теперь необходимо в нечетные элементы # помещать ассоциативные ключи, которые будут связываться со значениями, идущими за ними. (key1, value1, key2, value2) ; # Чтобы подчеркнуть то, что в переменной хранится хеш-массив, используется символ '%'. %person = (name, "Larry", surname, "Wall"); # Здесь 'name' ассоциативный ключ к скаляру "Larry", а 'surname' — к "Wall". # Чтобы обратиться к элементу хеш-массива по ключу, используется синтаксис $имя-хеш-массива{"ключ"}. print "Name: $person{name}\nSurname: $person{surname}\n"; # Создание массива через такой конструктор удобен, когда вы преобразуете обычный массив в хеш-массив. # В большинстве случаев следующий способ объявления хеш-массива удобнее. %person = ( name => "Larry", surname => "Wall" ); print "Name: $person{name}\nSurname: $person{surname}\n"; </source> В последнем случае оператор <code>=></code> аналогичен запятой с той разницей, что левый операнд всегда должен быть строковым литералом. Также обратим внимание, что запятую можно поставить в конце и для второго ключа, и это не будет ошибкой <source lang="perl"> %person = ( name => "Larry", surname => "Wall", # запятая здесь не ошибка ); </source> Для добавления нового элемента в хеш-массив или изменения существующего, достаточно просто обратиться по ключу. Если элемента не было, то он будет создан. <source lang="perl"> %person = ( name => "Larry", surname => "Wall" ); print %person, "\n"; $person{name} = "Garry"; # Значение по существующему ключу будет изменено $person{phone} = 1234; # Новое значение будет добавлено print %person, "\n"; delete($person{name}); # Удалить существующий элемент можно с помощью функции delete print %person, "\n"; </source> Для хеш-массивов существуют две встроенные функции, которые позволяют распечатать либо все ключи, либо все значения в массиве. <source lang="perl"> %person = ( name => "Larry", surname => "Wall", phone => 1234, ); print keys(%person), "\n"; # Печатает все ключи хеш-массива print values(%person), "\n"; # Печатает все значения хеш-массива </source> Для хеша тоже можно получить срез, однако, запись этого может немного вас запутать: <source lang="perl"> %fruits = ( apples => 32, bananas => 16, pears => 7, pineapples => 45, oranges => 21 ); print "@fruits{apples, oranges, pears}\n"; # Вывод: # 32 21 7 </source> Обратите внимание, что для получения среза хеша нужно использовать символ <code>@</code>, как в массиве, но индексация по ключам идет через фигурные скобки. == Удаление элементов из массивов == В рамках данной главы мы также рассмотрим способы удаления элементов из массивов, чтобы не возвращаться к этому. Элементы в массивах скаляров и хеш-массивах могут быть удалены несколькими способами, в зависимости от того, что вам нужно в конкретный момент. Если нужно удалить произвольный элемент(ы), можно воспользоваться функцией <code>delete</code>, которой нужно передать элемент по индексу для массивов (или вычисленный срез из элементов), либо указать элемент по ключу — для хешей. Функция <code>delete</code> возвращает значение удаляемого элемента. <source lang="perl"> # Создаем массив из 10 элементов @arr = (1..10); # Примечание: функция scalar заставляет интерпретировать выражение в скалярном контексте. print "Size: " . scalar @arr . "\n@arr\n"; # Удаляем элемент по индексу delete $arr[4]; print "Size: " . scalar @arr . "\n@arr\n"; # Примечание: функция exists возвращает ИСТИНУ, если элемент инициализирован. print STDOUT (exists $arr[4] ? "element exists" : "element doesn't exist") . "\n"; # Удаляем элементы по срезу delete @arr[1,3,6..8]; print "Size: " . scalar @arr . "\n@arr\n"; # Создаем хеш %hash = ( apple => 25, pear => 40, grapes => 100 ); # Примечание: функция keys возвращает массив ключей хеша. print "Hash size (before): " . (scalar keys %hash) . "\n"; # Удаляем элемент внутри хеша delete $hash{pear}; print "Hash size (after): " . (scalar keys %hash) . "\n"; # Следующие конструкции позволяют удалить все элементы из массива и хеша. # Примечание: данный метод удаления не самый оптимальный в плане производительности. delete @arr[0 .. $#arr]; delete @hash{keys %hash}; print "Array size: " . scalar @arr . "\n"; print "Hash size: " . (scalar keys %hash) . "\n"; # Массивы можно удалить быстрее просто обнулив ссылки на них. undef @arr; undef %hash; print "Array completely deleted\n" unless @arr; print "Hash completely deleted\n" unless %hash; </source> Вывод программы будет следующим: <pre> Size: 10 1 2 3 4 5 6 7 8 9 10 Size: 10 1 2 3 4 6 7 8 9 10 element doesn't exist Size: 10 1 3 6 10 Hash size (before): 3 Hash size (after): 2 Array size: 0 Hash size: 0 Array completely deleted Hash completely deleted </pre> Обратите внимание, что если в массиве скаляров остается хотя бы один элемент после удаления, инициированный размер массива уменьшаться никогда не будет. При этом в хэшах удаление элемента ведет к изменению реального размера. Если вам требуется пересчет размера массива, необходимо использовать специальные функции для работы с массивами. Например, если вам требуется добавлять или извлекать элементы массива с его краёв, вы можете использовать функции <code>push</code>, <code>pop</code>, <code>shift</code> и <code>unshift</code>: <source lang="perl"> @arr = (0); # Вставляет элементы из списка в конец массива. push @arr, (1,2,3); print "Size: " . scalar @arr . "\n@arr\n"; # С помощью pop извлекаем элементы в цикле с правого края. while ( defined ($element = pop @arr) ) { print "Poped: $element, Size: " . scalar @arr . "\n@arr\n"; } push @arr, (1..5); print "Size: " . scalar @arr . "\n@arr\n"; # Извлекает крайний левый элемент массива. $element = shift @arr; print "Left element: $element, Size: " . scalar @arr . "\n@arr\n"; # Вставляет элементы из списка в начало массива. unshift @arr, (6,7); print "Size: " . scalar @arr . "\n@arr\n"; </source> Вывод будет таким: <pre> Size: 4 0 1 2 3 Poped: 3, Size: 3 0 1 2 Poped: 2, Size: 2 0 1 Poped: 1, Size: 1 0 Poped: 0, Size: 0 Size: 5 1 2 3 4 5 Left element: 1, Size: 4 2 3 4 5 Size: 6 6 7 2 3 4 5 </pre> Если требуется удаление элементов с произвольной позиции с пересчетом размера, необходимо использовать функцию <code>splice</code>: <source lang="perl"> splice <array>[,<offset>[,<length>[,<list>]]] </source> Данная функция удаляет в массиве <code><array></code> <code><length></code> элементов, начиная со смещения <code><offset></code> и заменяет их элементами из списка <code><list></code>. Все аргументы функции, кроме первого, являются необязательными. Если нет списка <code><list></code>, то элементы будут просто удаляться, а если ничего кроме <code><array></code> не указано — удалено будет всё. <source lang="perl"> @arr = (1..10); print "Size: " . scalar @arr . "\n@arr\n"; # Примечание: # * Обратите внимание, что отсчет смещения начинается с нуля, т.е. смещение 4 # означает 5-й элемент по порядку. # * Функция делает замену из <list> один к одному. # Если размер изменяемых элементов <length> не равен размеру <list>, # функция просто удалит элементы из @arr, которые вышли за предел размера <list>. # Если <length> меньше размера <list>, функция будет использовать размер <list> вместо <length>. # # # Сравните: # Заменит элементы 5, 6, 7 соответственно на 0, 0 и 0. splice @arr, 4, 3, (0, 0, 0); print "Size: " . scalar @arr . "\n@arr\n"; # Размер <length> больше размера <list>, а значит 8-й элемент будет удален. splice @arr, 4, 4, (0, 0, 0); print "Size: " . scalar @arr . "\n@arr\n"; # Размер <length> меньше размера <list>, а значит 7-й элемент будет равен -1. splice @arr, 4, 3, (0, 0, -1); print "Size: " . scalar @arr . "\n@arr\n"; # Удаляем первые 3 элемента splice @arr, 0, 3; print "Size: " . scalar @arr . "\n@arr\n"; </source> Результат: <pre> Size: 10 1 2 3 4 5 6 7 8 9 10 Size: 10 1 2 3 4 0 0 0 8 9 10 Size: 9 1 2 3 4 0 0 0 9 10 Size: 9 1 2 3 4 0 0 -1 9 10 Size: 6 4 0 0 -1 9 10 </pre> == О переменных == Переменная в Perl не может быть рассмотрена вне контекста типов данных и операций, поэтому в этом разделе мы ограничимся только общими словами. * Переменная в Perl, как и в любом языке программирования, это именованный участок памяти. Первый символ перед именем переменной определяет ее тип: <code>$</code> (скаляр), <code>@</code> (массив скаляров), <code>%</code> (хеш-массив). * Имя переменной чувствительно к регистру и может состоять из цифр, букв и символа нижнего подчеркивания и не должно начинаться с цифры, а также не должно совпадать с зарезервированным в Perl словом. В Perl может быть создано три одноименных переменных, каждая из которых хранит по отдельному типу данных, например <code>$var</code>, <code>@var</code> и <code>%var</code>. Это возможно потому, что интерпретатор хранит имена переменных в разных списках для разных типов внутри таблицы символов пакета (о чём будет рассказано в поздних главах). * В выражениях, когда в качестве операнда используется некоторый тип, его интерпретация может зависеть от контекста, в котором он вычисляется, в частности существует два контекста: ''скалярный'' и ''списковый'' (''векторный''). Это важно, так как от этого будет зависеть конечный результат выражения. Об этом будет подробно рассказано, когда речь пойдет об операциях. * Любая переменная может находиться в состоянии определена или не определена. Переменная считается определенной, если ей присвоено какое-то значение. Чтобы определить статус переменной, следует пользоваться встроенной функцией <code>defined</code>.<source lang="perl"> print "not defined\n" if ! defined $arg; $arg = 1; print "defined\n" if defined $arg; $arg = undef; print "not defined\n" if ! defined $arg; # Результат: # not defined # defined # not defined </source> * Переменную можно сделать неопределенной, если вызвать функцию <code>undef</code>. Вызов этой функции будет приводить к освобождению памяти от ненужных данных. * Любая переменная имеет некоторую видимость относительно других участков программы. Видимость зависит от того, где и как переменная объявлена. Например, в вышеприведенных примерах все переменные были объявлены в глобальной области видимости. Когда переменная выходит из своей области видимости, она уничтожается. == Примечания == {{примечания}} kdgg3n9h7xms95a5efqwv6l8cg58fwv Некоторые сведения о Perl 5/Операции и выражения 0 30390 269876 265588 2026-08-27T10:03:54Z ScriptMaster 15708 /* Списковые операции */ 269876 wikitext text/x-wiki {{Навигация учебника}} ''Операция'' — это некоторые действия над операндами, результатом которых является новое значение. В Perl есть десятки операций, большинство из которых мы рассмотрим в этой главе, а другие в последующих. Операции можно делить по типу выполняемых ими действий (например, арифметические, логические и т.д.), по объекту, на который они воздействуют (строковые, списковые, файловые), а иной раз сложно отнести их к какой-то категории. Большинство операций работает с двумя операндами, которые записываются по обе стороны от знака операции (''бинарная операция''). Например в операции сложения операндами выступают слагаемые. Для других операций может требоваться один операнд (''унарная операция'') или три (''тернарная операция''). В некоторых операциях какие-то операнды можно опускать. Серия операций, записанная единым куском образует ''выражение''. Любое выражение интерпретируется слева направо, при этом порядок исполнения операций внутри выражения зависит от приоритета операций. Приоритеты операций в выражении можно менять через круглые скобки, которые дают более высокий приоритет. == Арифметические операции == {|class="wikitable" style="width:100%;" |- ! Операция ! Пример ! Описание ! Операция ! Пример ! Описание |- | colspan="6" | <center>'''Арифметические операции'''</center> |- |<center><code>+</code></center> |style="width:10%;"|<center><code>6.35+8.31</code></center> |style="width:30%;"|'''Сложение'''. Выполняет арифметическое сложение |<center><code>-</code></center> |style="width:10%;"|<center><code>9.15-5</code></center> |style="width:30%;"|'''Вычитание'''. Выполняет арифметическое вычитание |- |<center><code>*</code></center> |<center><code>2*2</code></center> |'''Умножение''' |<center><code>/</code></center> |<center><code>15/3</code></center> |'''Деление''' |- |<center><code>**</code></center> |<center><code>4**2</code></center> |'''Возведение в степень''' |<center><code>%</code></center> |<center><code>10%5</code></center> |'''Остаток от деления''' |- | colspan="6" | <center>'''Унарные арифметические операции'''</center> |- |<center><code>+</code></center> |<center><code>+5</code></center> |'''Унарный плюс''' |<center><code>-</code></center> |<center><code>-6</code></center> |'''Унарный минус'''. Делает положительное число отрицательным, а отрицательное — положительным |- | colspan="6" | <center>'''Инкремент/декремент'''</center> |- |<center><code>++</code></center> |<center><code>$i = 5, $j=$i++;</code></center> |'''Постфиксный инкремент'''. Увеличивает значение переменной на единицу после всех прочих операций над переменной. В примере значение в <code>$j</code> будет 5, а в <code>$i</code> значение будет 6, потому что инкремент выполняется после присваивания |<center><code>++</code></center> |<center><code>$i = 5, $j=++$i;</code></center> |'''Префиксный инкремент'''. В отличие от постфиксного инкремента, значение в операнде будет увеличено до всех прочих операций над ним. В данном примере в обеих переменных будет 6 |- |<center><code>--</code></center> |<center><code>$i = 5, $j=$i--;</code></center> |'''Постфиксный декремент'''. Уменьшает значение переменной на единицу после всех прочих операций над переменной. В примере значение в <code>$j</code> будет 5, а в <code>$i</code> значение будет 4, потому что декремент выполняется после присваивания |<center><code>--</code></center> |<center><code>$i = 5, $j=--$i;</code></center> |'''Префиксный декремент'''. В отличие от постфиксного декремента, значение в операнде будет уменьшено до всех прочих операций над ним. В данном примере в обеих переменных будет 4 |} * В основном арифметические операции направлены на работу с числами, однако операндами могут выступать и строки, причем не обязательно, чтобы они конвертировались в числа. В таких случаях интерпретатор сначала попытается выделить число из символов, начиная с первого. Если выделить число не получается, то результатом конвертации будет 0. Так, строка <code>5gh4</code> будет конвертирована в 5, а <code>g130</code> — в 0. * Если в операции остаток от деления (<code>%</code>) второй операнд является вещественным числом и имеет дробную часть, то он предварительно преобразуется в целое число путем простого отброса дробной части. * Отрицательное число <u>нельзя</u> возводить не в целую степень. Интерпретатор не будет выдавать никакой ошибки, но при этом результат всегда будет 0. * Бинарные арифметические операции выполняются в ''скалярном контексте''. Это означает, что интерпретатор будет ожидать в операндах скалярные переменные. Если в операндах будут массивы, то они будут преобразованы к числу элементов в массиве, а в случае хеш-массива — к числу использованных хеш-записей в нем. * Инкремент и декремент можно применять к строковым данным. В случае инкремента, если строка состоит только из латинских букв, то результатом будет новая строка, в которой последняя буква будет заменена на следующую по порядку в алфавите, причем строчная буква заменяется строчной, а прописная — прописной. Аналогично происходит, если строка завершается цифрой. Для декремента Perl будет пытаться конвертировать строку в число по обычным правилам, описанным выше. == Строковые операции == {|class="wikitable" style="width:100%;" |- ! Операция ! Пример ! Описание ! Операция ! Пример ! Описание |- | colspan="6" | <center>'''Строковые операции'''</center> |- |<center><code>.</code></center> |style="width:10%;"|<center><code>"a"."b"</code></center> |style="width:30%;"|'''Конкатенация строк'''. Объединяет две строки в одну |<center><code>x</code></center> |style="width:10%;"|<center><code>"a" x 3</code></center> |style="width:30%;"|'''Повторитель'''. Повторяет строку в левом операнде N число раз и возвращает из этого строку |} * Строковые операции обычно направлены на строковый тип данных, однако можно использовать и числа. В этом случае числа будут преобразованы в строки. * Оператор конкатенации не вставляет пробелы между строками. Обычно для объединения с пробелами прибегают к функции <code>join</code>. * Для операции ''повторения'' левый операнд всегда приводится к строковому значению. Правым операндом должно быть целое число, либо строка, которая может быть приведена к целому числу. В случае вещественного числа, дробная часть будет просто отбрасываться. * Для операции ''повторения'' левым операндом может быть список слов, заключенный в круглые скобки, т.е. эта операция может работать в ''списковом контексте''. В таком случае список будет повторен указанное число раз. Такой прием используется для порождения списка, передаваемого конструктору массива. * Знак операции повторения следует всегда отделять хотя бы одним пробелом от его операндов, так как в некоторых ситуациях интерпретатор может принять его за часть имени переменной. * С операцией повторения связана устойчивая идиома, используемая для быстрого заполнения одинаковыми значениями:<source lang="perl"> @arr[1..5] = (1) x 5; print "@arr\n"; # 1 1 1 1 1 @hash{qw{ apples bananas pears }} = (0) x 3; print "@{[%hash]}\n"; # apples 0 bananas 0 pears 0 </source>Если в левом операнде операции повторения используется массив, то операция будет выполняться в списковом контексте, в котором она повторит элементы указанное число раз в новом массиве. Если этот массив присвоить срезу массива или хэша (слева от присваивания), то сгенерированные повторением элементы будут присвоены элементам среза. На практике часто используется прием получения хеша из параметров командной строки, переданных сценарию:<source lang="perl"> my %exists; @exists{@ARGV} = (1) x @ARGV; # \ \____ В скалярном контексте развернется в число элементов массива @ARGV. # \___________________ Получается хеш, в котором ключами будут элементы командной строки. </source> == Логические операции == === Операции отношения === {|class="wikitable" style="width:100%;" |- ! Операция ! Пример ! Описание ! Операция ! Пример ! Описание |- | colspan="6" | <center>'''Числовые отношения'''</center> |- |<center><code>></code></center> |style="width:10%;"|<center><code>2>1</code></center> |style="width:30%;"|'''Больше'''. Возвращает 1, если ИСТИНА и <code>""</code>, если ЛОЖЬ |<center><code>>=</code></center> |style="width:10%;"|<center><code>3>=1</code></center> |style="width:30%;"|'''Больше либо равно'''. Возвращает 1, если ИСТИНА и <code>""</code>, если ЛОЖЬ |- |<center><code><</code></center> |<center><code>-3<0</code></center> |'''Меньше'''. Возвращает 1, если ИСТИНА и <code>""</code>, если ЛОЖЬ |<center><code><=</code></center> |<center><code>0<=3</code></center> |'''Меньше либо равно'''. Возвращает 1, если ИСТИНА и <code>""</code>, если ЛОЖЬ |- |<center><code>==</code></center> |<center><code>3==3</code></center> |'''Равно'''. Возвращает 1, если ИСТИНА и <code>""</code>, если ЛОЖЬ |<center><code>!=</code></center> |<center><code>1!=2</code></center> |'''Не равно'''. Возвращает 1, если ИСТИНА и <code>""</code>, если ЛОЖЬ |- |<center><code><=></code></center> |<center><code>15<=>63</code></center> |'''Один из операндов больше другого'''. Возвращает -1, если правый операнд больше левого; 1 — правый операнд меньше левого; 0 — операнды равны | | | |- | colspan="6" | <center>'''Строковые отношения'''</center> |- |<center><code>eq</code></center> |<center><code>"a" eq "a"</code></center> |'''Строки лексикографически равны'''. Возвращает "1", если ИСТИНА и <code>""</code>, если ЛОЖЬ |<center><code>ne</code></center> |<center><code>"a" ne "b"</code></center> |'''Строки лексикографически не равны'''. Возвращает "1", если ИСТИНА и <code>""</code>, если ЛОЖЬ |- |<center><code>lt</code></center> |<center><code>"a" lt "c"</code></center> |'''Левая строка лексикографически меньше правой'''. Возвращает "1", если ИСТИНА и <code>""</code>, если ЛОЖЬ |<center><code>le</code></center> |<center><code>"a" le "c"</code></center> |'''Левая строка лексикографически меньше или равна правой'''. Возвращает "1", если ИСТИНА и <code>""</code>, если ЛОЖЬ |- |<center><code>gt</code></center> |<center><code>"d" gt "e"</code></center> |'''Левая строка лексикографически больше правой'''. Возвращает "1", если ИСТИНА и <code>""</code>, если ЛОЖЬ |<center><code>ge</code></center> |<center><code>"d" ge "e"</code></center> |'''Левая строка лексикографически больше или равна правой'''. Возвращает "1", если ИСТИНА и <code>""</code>, если ЛОЖЬ |- |<center><code>cmp</code></center> |<center><code>"a" cmp "b"</code></center> |'''Лексикографически один из операндов не равен другому'''. Возвращает -1, если правый операнд лексикографически больше левого; 1 — правый операнд лексикографически меньше левого; 0 — операнды лексикографически равны | | | |} * Обратите внимание, что операции отношения скопированы с командной оболочки Bourne Shell, но там все было наоборот: <code>eq</code>, <code>ne</code>, <code>lt</code>, <code>le</code>, <code>gt</code> и <code>ge</code> применялись к числам, а привычные нам знаки использовались для лексикографического сравнивания. Об этом нужно помнить, когда вы переключаетесь с программирования для командной оболочки на программирование для Perl. * Лексикографическое сравнивание означает, что сравниваются ASCII кодировки символов. Так символ <code>a</code> лексикографически будет меньше символа <code>b</code>, потому что код последнего (98) больше первого (97). При лексикографическом сравнивании строк учитывается код каждого символа в строке, а также длина строк. * ИСТИНА для числовых отношений это число 1, а для строковых — строка <code>"1"</code>. * В общем случае следует быть осторожным при сравнивании вещественных чисел с целыми, так как тут вступает фактор округления чисел. Следует отметить, что вещественные числа вообще нельзя сравнивать на равенство, так как результат практически всегда будет неправильным. В этом случае следует сравнивать разницу двух вещественных чисел с очень малым числом (погрешностью). Можно использовать и другой приём, когда числа преобразуются в строки и сравниваются как строки. === Булевы выражения === {|class="wikitable" style="width:100%;" |- ! Операция ! Пример ! Описание ! Операция ! Пример ! Описание |- | colspan="6" | <center>'''Булевы операции'''</center> |- |<center><code>&&</code></center> |style="width:10%;"|<center><code>1 && 1</code></center> |style="width:30%;"|'''Конъюнкция''' |<center><code><nowiki>||</nowiki></code></center> |style="width:10%;"|<center><code><nowiki>0 || 1</nowiki></code></center> |style="width:30%;"|'''Дизъюнкция''' |- |<center><code>!</code></center> |<center><code>! 0</code></center> |'''Логическое отрицание''' |<center><code>xor</code></center> |<center><code>1 xor 1</code></center> |'''Исключающее ИЛИ''' |- |<center><code>and</code></center> |<center><code>1 and 1</code></center> |'''Конъюнкция'''. ''Синоним'' |<center><code>or</code></center> |<center><code>0 or 1</code></center> |'''Дизъюнкция'''. ''Синоним'' |- |<center><code>not</code></center> |<center><code>not 1</code></center> |'''Логическое отрицание'''. ''Синоним'' |<center><code>^^</code></center> |<center><code>1 ^^ 1</code></center> |'''Исключающее ИЛИ'''<ref>Знак операции появился с версии интерпретатора 5.40.</ref> |} * Операции <code>or</code>, <code>and</code>, <code>not</code> и <code>xor</code> появились в Perl, начиная с версии 5.001. Отличие их от аналогичных операций в виде символов в том, что они имеют меньший приоритет при вычислении в сложных выражениях. Такой пониженный приоритет иногда требуется в выражениях по типу <code>$num != 0 or print "\$num == 0";</code> * Для булевых операций ИСТИНОЙ признается любое скалярное значение не равное <code>0</code>, <code>"0"</code> и <code>""</code>, в противном случае это ЛОЖЬ. Значение <code>undef</code> также приравнивается ко ЛЖИ. * Булевы операции конъюнкции и дизъюнкции вычисляются по укороченной схеме. Это означает, например, что если при конъюнкции ЛОЖЬ в некотором операнде встречается раньше, чем закончилось выражение, вычисление прекращается на этом операнде с общим результатом ЛОЖЬ. * Хотя булевы операции рассчитаны в основном на то, чтобы использовать их с числами, некоторые из них можно использовать для работы со строками. Полезной здесь оказывается дизъюнкция, которая может быть использована для записи укороченного присваивания значений по умолчанию, что показано в следующем примере: <source lang="perl"> # Эта процедура просто возвращает строку, переданную в аргументе, но если он не передается, # то она назначит ему значение по умолчанию. sub procedure { my ($arg) = @_; $arg ||= "default_value"; return $arg; } # Вызов без аргумента print "Result: " . procedure . "\n"; # Result: default_value # Вызов с аргументом print "Result: " . procedure "some_value" . "\n"; # Result: some_value </source> Также, в случаях, когда неопределенные значения недопустимы, она может использоваться для выбора из альтернативы: <source lang="perl"> $var = undef; $var = $var || "default_value"; print "$var\n"; # default_value # Размер цепочки может быть сколько угодно большим. В данном примере мы использовали # undef для демонстрации, но представьте на их местах переменные. Значение по умолчанию # выбирается с разным приоритетом (первое не пустое с левого края). $value = undef || undef || undef || "default_value"; print "$value\n"; </source> === Побитовые операции === {|class="wikitable" style="width:100%;" |- ! Операция ! Пример ! Описание ! Операция ! Пример ! Описание |- | colspan="6" | <center>'''Побитовые операции'''</center> |- |<center><code><nowiki>&</nowiki></code></center> |style="width:10%;"|<center><code>3 & 2</code></center> |style="width:30%;"|'''Побитовое И'''. Выполняет конъюнкцию двух чисел побитово |<center><code><nowiki>|</nowiki></code></center> |style="width:10%;"|<center><code><nowiki>3 | 2</nowiki></code></center> |style="width:30%;"|'''Побитовое ИЛИ'''. Выполняет дизъюнкцию двух чисел побитово |- |<center><code>^</code></center> |<center><code>3 ^ 3</code></center> |'''Побитовое исключающее ИЛИ''' |<center><code>~</code></center> |<center><code>~0</code></center> |'''Побитовое отрицание''' |- |<center><code><<</code></center> |<center><code>1 << 1</code></center> |'''Побитовый сдвиг влево''' |<center><code>>></code></center> |<center><code>2 >> 1</code></center> |'''Побитовый сдвиг вправо''' |} * Побитовые операции работают только с числами, если хотя бы один операнд является числом (соответственно другой будет сконвертирован в число). Если '''оба''' операнда являются строками, то побитово выполняются операции с кодом каждого символа, даже если строки записаны только цифрами. Если при этом строки разной длины, то меньшая из них дополняется символами <code>\000</code> до равенства. * Все вещественные числа преобразуются к целым. * Допустимо использовать любой формат представления чисел: десятичный, шестнадцатеричный и восьмеричный. Язык Perl представляет числа с длиной 32 бит для поразрядных операций, независимо от архитектуры компьютера. == Операции присваивания == {|class="wikitable" style="width:100%;" |- ! Операция ! Пример ! Описание ! Операция ! Пример ! Описание |- | colspan="6" | <center>'''Операции присваивания'''</center> |- |<center><code>=</code></center> |style="width:10%;"|<center><code>$i = 2</code></center> |style="width:30%;"|'''Простое присваивание''' |<center><code>**=</code></center> |style="width:10%;"|<center><code>$i **= 2</code></center> |style="width:30%;"|'''Возведение в степень с присваиванием''' |- |<center><code>+=</code></center> |<center><code>$i += 2</code></center> |'''Сложение с присваиванием''' |<center><code>-=</code></center> |<center><code>$i -= 2</code></center> |'''Вычитание с присваиванием''' |- |<center><code>.=</code></center> |<center><code>$i .= 2</code></center> |'''Конкатенация с присваиванием''' |<center><code>*=</code></center> |<center><code>$i *= 2</code></center> |'''Умножение с присваиванием''' |- |<center><code>/=</code></center> |<center><code>$i /= 2</code></center> |'''Деление с присваиванием''' |<center><code>%=</code></center> |<center><code>$i %= 2</code></center> |'''Остаток от деления с присваиванием''' |- |<center><code>x=</code></center> |<center><code>$i x= 2</code></center> |'''Повторение с присваиванием''' |<center><code>&=</code></center> |<center><code>$i &= 2</code></center> |'''Поразрядное И с присваиванием''' |- |<center><code><nowiki>|=</nowiki></code></center> |<center><code><nowiki>$i |= 2</nowiki></code></center> |'''Поразрядное ИЛИ с присваиванием''' |<center><code>^=</code></center> |<center><code>$i ^= 2</code></center> |'''Поразрядное исключающее ИЛИ с присваиванием''' |- |<center><code><<=</code></center> |<center><code>$i <<= 2</code></center> |'''Поразрядный сдвиг влево с присваиванием''' |<center><code>>>=</code></center> |<center><code>$i >>= 2</code></center> |'''Поразрядный сдвиг вправо с присваиванием''' |- |<center><code>&&=</code></center> |<center><code>$i &&= 2</code></center> |'''Конъюнкция с присваиванием''' |<center><code><nowiki>||=</nowiki></code></center> |<center><code><nowiki>$i ||= 2</nowiki></code></center> |'''Дизъюнкция с присваиванием''' |- |<center><code>^^=</code></center> |<center><code>$i ^^= 1</code></center> |'''Исключающее ИЛИ с присваиванием'''<ref>Поддерживается с версии 5.42.</ref> | | | |} * Простое присваивание является бинарной операцией, правый операнд которой является выражением, а левый — определяет участок памяти (в форме переменной), в который запишется результат выражения. Операция присваивания возвращает левый операнд как результат выражения. По этой причине следующая запись будет синтаксически правильной<source lang="perl"> ($i = $j) = 5; # Если развернуть эту конструкцию, то получается $i = $j; $i = 5; # Так как выражение в скобках вернет $i </source> * Как в языке Си, в Perl есть составное присваивание, совмещающее в себе операцию и присваивание. Операции с присваиванием также возвращают левый операнд, как результат выражения<source lang="perl"> $b = 1; $a = ($b += 3); # Аналогично $a = $b = 4 $a += ($b += 3); # Аналогично $a = $a + $b + 3 (($a += 2) **= 2 ) -= 1; # Аналогично $a = ($a + 2) ** 2 - 1 </source>Обратим внимание, что в большинстве ситуаций в сложных выражениях ставить скобки для операций присваивания обязательно, потому что, как вы узнаете ниже, они парсятся интерпретатором справа налево. == Списковые операции == ''Списковая операция'' — это операция над списком значений. Операции, которым передаются списки и кажущиеся функциями, на самом деле являются списковыми операциями, например <code>print</code>. Это связано с тем, что списковые операции разрешают помещать свои аргументы в скобки. Так, следующие вызовы равнозначны <source lang="perl"> print $a, "hello", $b; print ($a, "hello", $b); </source> Списковые операции ожидают на входе список скаляров в некоторой форме, а на выходе отдают тот же список, но модифицированный некоторым образом, либо новый список. Так, следующие операции являются списковыми: * Создание и конкатенация массивов<source lang="perl"> @array1 = (1,2,3); @array2 = (4,5,6); @array3 = (@array1, @array2); </source> * Встроенные операции, связанные с манипуляцией значением(ми) в массиве<source lang="perl"> @array = (1,2,3); push @array, 4; # (1, 2, 3, 4) pop @array; # (1, 2, 3); 4 возвращается как результат shift @array; # (2, 3); 1 возвращается как результат unshift @array, 5; # (5, 2, 3) splice @array, 0, 2; # (3); (5, 2) возвращается как результат </source> * Трансформация (новый массив возвращается как результат)<source lang="perl"> @array = qw { a b c d e f }; # Применение предиката к каждому элементу в списке print "$_\n" foreach map { $_ . $counter++ } @array; # # Вызов map в модификаторе foreach возвращает новый массив, каждый элемент которого # печатается print слева от модификатора. В этом примере процедура предиката к каждому # элементу исходного массива добавляет порядковый номер, в результате чего получается # # a0 # b1 # c2 # d3 # e4 # f5 # # Сформировать новый массив, элементы которого хранятся в обратном порядке print "$_\n" foreach reverse @array; # f # e # d # c # b # a # Сортировка use List::Util; # Подключаем модуль для перемешивания элементов для дальнейшего примера. @array = List::Util::shuffle(@array); # Перемешиваем элементы в случайном порядке. print "@{array}\n"; # Вывод будет отличаться при каждом вызове: "b f d a e c" @array = sort @array; # Снова в алфавитном порядке. print "@{array}\n"; # "a b c d e f" </source> * Фильтрующие операции (возвращают подмножество исходного массива как результат)<source lang="perl"> @array = qw { a 1 5 d 6 f 8 9 h j k l 25 }; @numbers = grep /\d+/, @array; # Достаем из исходного массива только цифры print "@{numbers}\n"; # "1 5 6 8 9 25" @letters = grep /[a-z]+/, @array; # Достаем из исходного массива только буквы print "@{letters}\n"; # "a d f h j k l" </source> * Агрегирующие операции (как правило, возвращают все элементы массивов одним значением)<source lang="perl"> @words = qw { apple grapes banana }; $value = join ", ", @words; # объединяет все элементы и вставляет между ними разделитель. print "${value}\n"; # "apple, grapes, banana" </source> * Разворачивающие операции (наоборот, из одного значения получают список)<source lang="perl"> @numbers = 1..5; print "@{numbers}\n"; # "1 2 3 4 5" $fruits = "apple, banana, grapes"; @fruits = split ", ", $fruits; print "@{fruits}\n"; # "apple banana grapes" </source> Подробнее о пользовательских списковых операциях будет в главе, посвященной функциям. === Списковые операции all и any === Начиная с версии 5.42, в ядро интерпретатора были интегрированы две новые операции, помогающие работать со множествами без использования модулей. До этого эти операции приходилось подключать в виде функций из модуля <code>List::Util</code>. Вероятно, добавление этих операций в ядро было вдохновлено языком Python, в котором они существуют в виде операторов. <source lang="perl"> any { <блок-предиката> } @list; all { <блок-предиката> } @list; </source> Операции <code>all</code> и <code>any</code> мимикрируют под операцию <code>grep</code> и используются, чтобы вернуть логический ответ по предикату. Чтобы операция <code>all</code> вернула ИСТИНУ, необходимо чтобы её предикат вернул ИСТИНУ для каждого элемента списка. Соответственно, для операции any ИСТИНОЙ считается ситуация, когда предикат возвращает ИСТИНУ по меньшей мере для одного элемента списка. Появление этих операций, хоть и с опозданием, очень кстати, так как различного рода проверки множеств — частая задача на практике. Вот лишь несколько примеров. <source lang="perl"> use v5.42; # Директива требует интерпретатор не ниже указанной версии. # Следующие директивы нужны по крайней мере для версии 5.42, так как на тот момент # эти возможности были еще экспериментальными. В будущих версиях эти # директивы не понадобятся. use feature 'keyword_any', 'keyword_all'; # Включает операции no warnings 'experimental::keyword_any', 'experimental::keyword_all'; # Отключает предупреждения my @numbers = (2, 4, 6, 8, 10); if (all { $_ % 2 == 0 } @numbers) { print "All numbers are even\n"; } if (any { $_ > 9 } @numbers) { print "At least one number is greater than 9\n"; } </source> == Операции заключения в кавычки == Кавычки (одинарные, двойные и обратные) используются в Perl, чтобы задавать строковые литералы. Кроме этого есть еще операции, которые внешне похожи на операции заключения в кавычки, и перечислены в таблице ниже. {|class="wikitable" style="width:100%;" |- ! Операция ! Эквивалент ! Описание ! Операция ! Эквивалент ! Описание |- | colspan="6" | <center>'''Операции заключения в кавычки'''</center> |- |<center><code>q{}</code></center> |style="width:10%;"|<center><code><nowiki>''</nowiki></code></center> |style="width:30%;"|'''Строковый литерал'''. Подстановки невозможны |<center><code>qq{}</code></center> |style="width:10%;"|<center><code>""</code></center> |style="width:30%;"|'''Строковый литерал''' |- |<center><code>qx{}</code></center> |<center><code><nowiki>``</nowiki></code></center> |'''Команда системы''' |<center><code>qw{}</code></center> |<center><code><nowiki>()</nowiki></code></center> |'''Список слов'''. Подстановки невозможны |- |<center><code>m{}</code></center> |<center><code><nowiki>//</nowiki></code></center> |'''Поиск по регулярному выражению''' |<center><code>qr{}</code></center> |<center><code><nowiki>//</nowiki></code></center> |'''Шаблон регулярного выражения''' |- |<center><code>s{}{}</code></center> |<center><code>s///</code></center> |'''Подстановка''' |<center><code>tr{}{}</code></center> |<center><code><nowiki>y///</nowiki></code></center> |'''Транслитерация'''. Подстановки невозможны |} * Фигурные скобки в данных операциях представляют собой разделитель. Они могут быть в любой момент заменены на другой символ или любую другую пару скобок, например<source lang="perl"> q{hello} q/hello/ q!hello! q<\<hello\>> # Если символы разделителя есть в значении, то они должны экранироваться. </source>Внутри разделителей разрешается любое число пробелов, а также внутри большинства операций разрешены подстановки, кроме некоторых (указанных в таблице отдельно). * Операция <code>qw{}</code> позволяет вернуть список слов. Чаще всего она используется, чтобы инициализировать массив.<source lang="perl"> @arr = qw{ one two three }; # Это аналогично @arr = ("one", "two", "three"); # и $arr[0] = "one"; $arr[1] = "two"; $arr[2] = "three"; </source>Обратите внимание, что внутри <code>qw{}</code> запятые ставить не нужно: разделителями являются пробелы. * Об остальных операциях будет рассказано далее по ходу изложения. === Операция Here-docs === В Perl перекочевала Here-docs операция, придуманная для командной оболочки Bourne Shell, которая позволяет инициализировать переменные многострочными строками, либо передавать их на вход некоторой операции, записывая строки прямо в исходном файле программы. Как и в Bourne Shell она записывается так <source lang="perl"> $str = <<EOF; строка 1 строка 2 строка 3 EOF print <<END; Hello, World! END </source> Здесь после знака <code><<</code> вводится так называемое стоп-слово. Далее записывается многострочная строка. Интерпретатор будет искать стоп-слово, для того чтобы понять где заканчивается эта строка. Стоп-слово может быть любым строковым литералом. В наших примерах стоп-словами были <code>EOF</code> и <code>END</code>. За стоп-словом обычно следует ставить символ точки с запятой, так как Here-docs является простым оператором, конец которого находится после ввода стоп-слова. Пропуск точки с запятой является очень частой ошибкой. Тем не менее, если оператор Here-docs является единственным или последним в текущем блоке, точку с запятой можно опускать. По умолчанию многострочная строка записывается так, как будто она находится в двойных кавычках. Таким образом, в ней будут разрешаться все подстановки и управляющие последовательности. Вы можете явно обозначить, как должен поступать интерпретатор, если будете использовать соответствующие кавычки вокруг стоп-слова. <source lang="perl"> $var = "Hello"; print <<END; \t$var, World! END # Аналогично предыдущему вызову print <<"END"; \t$var, World! END # С одинарными кавычками переменные перестанут подставляться и # не будут работать управляющие последовательности print <<'END'; \t$var, World! END </source> Можно также использовать наклонные кавычки, тогда в Here-docs можно писать процедуры командной оболочки и инициализировать переменные результатом работы этих процедур. Каждая строка в таких процедурах это отдельный ввод команды в оболочку. Следует помнить, что результаты могут зависеть от операционной системы, в которой исполняется Perl. <source lang="perl"> # Выведет каталоги корневой точки монтирования в *nix системе. print <<`END`; ls -l / END </source> Если стоп-слово вводится без кавычек, то нельзя ставить пробелы между <code><<</code> и стоп-словом. Если такое случится, то Perl не распознает такого слова и будет захватывать строки до первой пустой строки в исходном файле. В одном операторе можно ввести больше одного стоп-слова (когда это удобно), если записать их подряд следующим образом. <source lang="perl"> print <<"END1".<<'END2'; double quotes END1 single quotes END2 </source> По умолчанию, Here-docs сохраняет все лидирующие пробелы в многострочной строке, а также требует, чтобы стоп-слово всегда находилось в первой колонке. Например, <source lang="perl"> print <<END; ONE TWO THREE END </source> напечатает <pre> ONE TWO THREE </pre> Такое поведение не всегда удобно, особенно, когда Here-docs вложена в некоторый блок: в этом случае в исходном коде нарушается выравнивание, из-за чего его неудобно читать. Сравните <source lang="perl"> # Операция размещена в блоке, но мы не можем выровнять отступы как нам хочется, а также # стоп-слово END должно всегда начинаться с первой колонки. if (1) { print <<END; ONE TWO THREE END } </source> С версии 5.26 для Here-docs была добавлена особая форма (<code><<~</code>), которая вычисляет отступ для многострочной строки не от колонки документа с исходным кодом, а от отступа самого стоп слова. Таким образом, с версии 5.26 тот же фрагмент можно записать с сохранением исходных отступов так: <source lang="perl"> # С версии 5.26 if (1) { print <<~END; ONE TWO THREE END # ^- отступ для многострочной строки вычисляется от этой колонки. } </source> Операция Here-docs может комбинироваться с другими операциями. Для этого удобно пользоваться мнемоническим приемом, в котором нужно представлять, что очередная строка заменяет собой стоп-слово справа от знака <code><<</code>. Вот несколько примеров: <source lang="perl"> # Каждая строка подается операции uc, которая переводит символы в верхний регистр. print uc(<<EOF); one two three EOF # Результат: # ONE # TWO # THREE # Удалит лидирующие пробелы для каждой строки. print <<'EOF' =~ s/^\s+//mgr; Line one with leading spaces Line two with leading spaces EOF # Результат: # Line one with leading spaces # Line two with leading spaces # При выводе строк будет приписывать к каждой порядковый номер. sub numbering { print ++$counter . ": " . $_ . "\n" for split '\n', $_[0]; } numbering(<<'EOF'); int main(int argc, char** argv) { return 0; } EOF # Результат: # 1: int main(int argc, char** argv) # 2: { # 3: return 0; # 4: } # Напечатает между строками промежуточную. print <<'PART1' . "Middle String\n" . <<'PART2'; This is the first part. PART1 This is the final part. PART2 # Результат: # This is the first part. # Middle String # This is the final part. </source> == Другие операции == === Диапазон === Бинарная операция диапазон <code>..</code> по-разному интерпретируется в скалярном и списковом контекстах. В списковом контексте операция возвращает список из чисел, начиная с левого операнда и до последнего с шагом 1, если оба операнда являются числами, либо строки, которые будут сгенерированы в лексикографическом порядке. Если операндами являются числа, то левый операнд всегда должен быть меньше правого, иначе операция вернет пустой список. Числа также должны быть всегда целыми (если это не так, то дробная часть будет просто отбрасываться). Если строка-левый операнд в лексикографическом смысле больше правого, то результат может зависеть от версии интерпретатора <code>perl</code>: в старых версиях по умолчанию просто возвращается левый операнд; в версии 5.32 будет возвращен ряд, начиная с большего операнда и до символа <code>z</code>. Кроме того, нельзя использовать символы из других алфавитов, кроме латинского: для других алфавитов всегда возвращается левый операнд как результат. <source lang="perl"> (1..5); # 1 2 3 4 5 (-3..5); # -3 -2 -1 0 1 2 3 4 5 ("a".."d"); # a b c d ("01".."10"); # 01 02 03 04 05 06 07 08 09 10 ("a1".."b2"); # a1 a2 a3 ... a9 b1 b2 </source> В скалярном контексте диапазон возвращает булево значение и эмулирует поведение операции запятая <code>,</code> из редакторов Sed и AWK (например, конструкция <code>1,3p</code>). Алгоритм поведения может показаться сложным при первом прочтении, тем не менее следует познакомиться с ним: * Диапазон в скалярном контексте всегда находится в одном из двух состояний, которое может измениться при повторном вычислении. Условно мы назовем их ИСТИНА и ЛОЖЬ. * Диапазон остается в ЛОЖНОМ состоянии до тех пор, пока ЛОЖНЫМ остается значение левого операнда. Как только он становится ИСТИНОЙ, диапазон переключает состояние в ИСТИНУ и остается в нем, пока правый операнд остается ИСТИННЫМ. * Если диапазон находился в состоянии ИСТИНА и правый операнд стал ЛОЖНЫМ, то диапазон снова переключается в ЛОЖНОЕ состояние и вся предыдущая логика повторяется заново. * В ЛОЖНОМ состоянии этот диапазон возвращает пустую строку (или ЛОЖЬ). В состоянии ИСТИНА при каждом повторном вычислении возвращается порядковый номер, начиная с 1. * В момент перехода из ИСТИНЫ в ЛОЖЬ диапазон возвращает строку, в которой к последнему порядковому номеру добавляется <code>"E0"</code>, например <code>2E0</code>. В ИСТИННОМ состоянии <code>E0</code> будет отбрасываться. Вот собственно и весь алгоритм. Добавление <code>"E0"</code> при смене состояния эмулирует поведение именно утилиты AWK. В Sed добавление этой строки происходит только на следующем вычислении. Чтобы эмулировать именно поведение Sed, нужно использовать три точки <code>...</code>. Диапазоны в скалярном контексте в Perl обычно используются при чтении файлов. === Операция запятая === Операция запятая <code>,</code> является бинарной и ведет себя по-разному в скалярном и списковом контекстах: * в списковом контексте она является разделителем для элементов в списке; * в скалярном контексте она сначала вычисляет левый операнд, потом правый и возвращает результат правого операнда как общий результат. <source lang="perl"> # Так как левый операнд присваивания это переменная на массив, то выражение исполняется в списковом контексте. # В этом примере запятая разделяет элементы списка, который передается конструктору массива. @arr = (1, 2); # Теперь выражение выполняется в скалярном контексте. Оба операнда для запятой являются простыми числами, но # как результат операции, будет возвращена 2, которая будет присвоена скаляру. $scalar = (1, 2); </source> У запятой есть синоним в виде <code>=></code>, который мы ранее использовали для построения хеш-массивов в конструкторе. В основном этот знак повторяет запятую, но требует чтобы левый операнд всегда имел строковый тип и корректно в него конвертировался. Операция является излюбленным инструментом трюков интерпретации. Например, следующая конструкция по порядку вызовет все процедуры, при этом в первой печати мы попутно захватываем результат вызова процедуры <code>b</code>, пользуясь тем, что операция используется в списковом контексте, в котором мы можем пользоваться индексацией массива, а во втором случае, выполняя все в скалярном контексте, мы получаем результат процедуры <code>c</code>: <source lang="perl"> sub a { print "1\n"; "a" } sub b { print "2\n"; "b" } sub c { print "3\n"; "c" } print STDOUT ( &a, &b, &c )[1], "\n"; print STDOUT scalar ( &a, &b, &c ), "\n"; </source> <pre> 1 2 3 b 1 2 3 c </pre> === Тернарная операция === В Perl есть тернарная условная операция, которая есть во многих языках программирования. Она записывается точно также как в Си: <source lang="perl"> <операнд 1> ? <операнд 2> : <операнд 3> </source> Операция работает так. Если <code><операнд 1></code> является ИСТИНОЙ, то возвращается <code><операнд 2></code> как результат тернарной операции, иначе возвращается <code><операнд 3></code>. Результат тернарной операции можно использовать как в левосторонних (''lvalue''), так и в правосторонних выражениях (''rvalue''), главное чтобы они подставлялись в правильном семантическом контексте. <source lang="perl"> $var = ($num % 3) ? ($var1 += 1) : ($var1 += 2); (($a % 3) ? ($a += 2) : $a) -= 2; # Пример с lvalue выражением </source> === Ссылочные операции === Большую часть времени мы ссылаемся на данные в памяти компьютера через переменные. Однако язык Perl, подобно Си, разрешает ссылаться на данные в памяти с помощью ''указателей'' или ''ссылок'' (в Perl эти термины равнозначны), которые хранят адрес на ячейку в памяти как значение. Ссылочная передача удобна, когда одни и те же данные разделяют множество процедур и при этом не нужно привязываться к конкретным именам или типам в тексте программы. Возможно процедура сама должна разобраться, что хранится в памяти по переданной ссылке и принять решение самостоятельно. Чтобы получить адрес переменной, нужно перед ее именем написать обратный слеш <code>\</code> (это аналогично операции получения адреса <code>&</code> в языке Си). <source lang="perl"> # Ссылка на скаляр $var = 5; $ptr = \$var; # Теперь здесь хранится адрес $var # Ссылка на массив @arr = (1,2,3); $aptr = \@arr; # Ссылка на хеш-массив %hash = (name => "Larry", surname => "Wall"); $hptr = \%hash; </source> Обратите внимание, что адреса хранятся в скалярной переменной. Если мы распечатаем значения, то получим примерно следующее: <source lang=""> SCALAR(0x800075938) ARRAY(0x8000759b0) HASH(0x800075aa0) </source> Обратите внимание, что в ссылке хранится информация о типе объекта, на который она ссылается и шестнадцатеричный адрес в памяти компьютера. Чтобы выполнить обратную операцию, т.е. получить данные по ссылке, ее нужно ''разыменовать''. В отличие от Си, в Perl разыменовывание привязано к типу данных, на который она ссылается. Для этого нужно перед именем ссылки поставить тип, на который будет вестись разыменовывание. <source lang="perl"> # Разыменовываем ссылку на хеш-массив, чтобы передать его функции keys, которая извлечет из него ключи @keys = keys(%$hptr); print $$ptr, "\n"; # Разыменовываем указатель на скаляр </source> В предыдущем примере с хеш-массивом мы сначала разыменовали ссылку на хеш-массив, указав символ <code>%</code> в начале, а только потом работали с массивом как обычно, передав его функции <code>keys</code>. Perl позволяет также обращаться к данным массивов непосредственно из ссылки (когда это удобно) при помощи операции разыменовывания массивов <code>-></code>. <source lang="perl"> print $aptr->[0], $hptr->{name}, "\n"; </source> Подробнее ссылки мы рассмотрим в отдельной главе (''см.'' [[{{Root book name}}/Ссылки|Ссылки]]). === Операции связывания === Регулярные выражения являются визитной карточкой Perl, который снабжен различными операциями для проверки по ним. Сюда входят поиск (<code>m//</code>), подстановка (<code>s///</code>) и замена (<code>tr///</code>). По умолчанию они работают с переменной <code>$_</code>. Кроме них есть операции связывания <code>=~</code> и <code>!~</code>, которые выражают соответственно ''совпадает с шаблоном'' и ''не совпадает с шаблоном''. Регулярные выражения являются очень обширной темой в Perl, поэтому они будут рассмотрены в отдельной главе (''см.'' [[{{Root book name}}/Работа со строками и регулярные выражения|Работа со строками и регулярные выражения]]). ==== Умное связывание ==== Начиная с 5.10.1 и до 5.37.10 в Perl поддерживалась операция умного связывания, которая умеет сравнивать переменные, хранящие разные типы данных. Данная бинарная операция обозначается двумя тильдами <code>~~</code> и изначально была введена для поддержки оператора <code>given..when</code> (в котором она используется неявно), о котором немного рассказано в следующей главе (см. [[Некоторые сведения о Perl 5/Операторы#Given..when|Операторы#Given..when]]). Эта операция является особенной, так как её контекст определяется не на этапе компиляции, а во время исполнения программы. Для этого она определяет какой тип данных хранится в её операндах и, в зависимости от этих типов, выбирает механизм сравнивания, причем фактические типы в операндах не обязательно должны совпадать, что и делает её «умной». Если в понимании выбранного механизма операнды равны, она возвращает 1, иначе пустую строку <code>""</code>. В Perl 5.37.10 данная операция была отмечена как неудачный эксперимент и окончательно будет вырезана в 5.42. Здесь мы о ней упоминаем, чтобы предостеречь не использовать её, хотя следует отметить сколько релизов ей удалось пережить. === Именованные унарные операции === В Perl есть большое число встроенных функций с одним аргументом, которые с точки зрения синтаксического анализатора являются ''унарными именованными операциями''<ref>Слово ''именованный'' подчеркивает тот факт, что у операции есть имя в виде обозначающего слова, при этом они не требуют скобок вокруг аргумента, копируя операции с одним символом.</ref>. Такие операции подобны функциям, но не требуют скобок вокруг параметра, как того требуют простые функции. О том, является ли функция такой операцией, можно узнать из документации. К таким операциям относятся например <code>do</code>, <code>eval</code>, <code>return</code>, <code>goto</code>, <code>sin</code>, <code>sqrt</code> и другие, а также все операции проверок файлов типа <code>-e</code> (файл существует), <code>-w</code> (в файл можно писать) и другие. Ключевая особенность именованных унарных операций в Perl заключается в их приоритете: они имеют более высокий приоритет, чем большинство бинарных операций, но ниже, чем скобки и операция стрелки (<code>-></code>). По ходу изложения мы затронем многие из этих операций. === Операции ввода/вывода === Это операции, которые направлены на вывод результатов в файлы или ввод данных в программу из них. Так, унарную именованную операцию <code>print</code> можно рассматривать как операцию вывода. Чтобы обеспечить ввод данных в программу из файлов, нужно сначала их открыть и получить специальный программный объект, называемый ''дескриптором файла''. Дескриптор файла может быть получен через операцию в виде угловых скобок <code><дескриптор_файла></code>: <source lang="perl"> open(DFILE, "net.cfg"); # Открываем файл. Идентификатор дескриптора DFILE может быть произвольным @content = <DFILE>; # Читаем файл в массив </source> Если бы мы открыли файл на запись, то мы можем перенаправить запись в него так <source lang="perl"> print MYFILE "Hello"; </source> Тема ввода/вывода является очень обширной, поэтому она будет рассмотрена в отдельной главе (''см.'' [[{{Root book name}}/Ввод и вывод|Ввод и вывод]]). == Выражения == Понимание того, как интерпретатор Perl парсит выражения, поможет вам лучше понять как они должны составляться. ''Выражение'' — это несколько операндов, объединенных одной и более операциями. Операнд в свою очередь также может быть выражением, т.е. одно общее выражение это конгломерат подвыражений. Синтаксический анализатор Perl, во время разбора выражения, пытается выделить в нем элементарные члены — ''термы''<ref>Если делать сравнение с естественным языком, то терм является тем же самым, что и ''слово'' в предложении.</ref>, а потом соединить их знаками операций, причем он выстраивает операции в некотором порядке, учитывая приоритет. В Perl термами являются литералы, переменные, выражения в скобках, закавыченная строка символов, а также функции с параметрами в скобках. Только терм может быть операндом. Отметим, что в Perl отсутствуют истинные функции: по существу они являются списковыми, унарными именованными операциями, ведущими себя как функции. Вызывая функцию, мы выполняем списковую или унарную операцию, которая возвращает некоторый результат. <source lang="perl"> # Следующее выражение демонстрирует списковую операцию. В ней сначала # вычисляется как терм каждый элемент списка, а затем каждый элемент выводится # на печать списковой операции. print 2 + 2 * 25 / 4, ' ', 16; # Напечатает '14.5 16' # Следующее выражение дает аналогичный результат. Избыточные скобки # порождают массив, передаваемый операции. print (2 + 2 * 25 / 4, ' ', 16); # Напечатает '14.5 16' # Теперь попробуем добавить конкатенацию: print (2 + 2 * 25 / 4, ' ', 16) . '$'; # Напечатает '14.5 16' # Обратите внимание, что результат конкатенации потерялся (нет символа '$' # в выводе). Это произошло потому, что левый операнд конкатенации, как терм # по приоритету вычисляется первым, т.е. print выводит результат своего терма # в аргументе, а не результат конкатенации. # Допустимо print print (2 + 2 * 25 / 4, ' ', 16) . '$'; # Напечатает '14.5 161$' # Появление единицы объясняется тем, что внутренний print вернул код 1, который # был преобразован в строку и был объединен конкатенацией # c '$'. Так как между внутренним и внешним print нет переноса # строки, получилась такая склеенная строка. </source> При синтаксическом разборе выражений и операторов, как термы рассматриваются конструкции <code>do{}</code> и <code>eval{}</code>, вызовы подпрограмм и методов объектов, анонимные конструкторы массивов скаляров и хешей, а также все операции ввода/вывода. Еще один немаловажный термин это ''контекст операции''. Операции и термы вычисляются в некотором контексте, от которого зависит поведение операции и возвращаемое ей значение. Существует два основных контекста: ''скалярный'' и ''списковый''. В скалярном контексте интерпретатор пытается вывести из терма скаляр, а в списковом контексте — список литералов <code>qw{}</code>. Контекст определяет обычно тип данных левого операнда. Так, если он является скаляром, то операция выполняется в скалярном контексте; если массив скаляров — списковом контексте. Некоторые операции способны распознавать в каком контексте они исполняются и возвращать свой результат в зависимости от него (универсальные операции). <source lang="perl"> # В списковой операции print перед списком можно указать выходной дескриптор: print STDOUT (2 + 2 * 25 / 4, ' ', 16) . '$'; # Напечатает '16$' # Потеря 14.5 Объясняется тем, что левый операнд конкатенации # находится в скалярном контексте, а в нем операция запятая # возвращает последний операнд как результат. # Уберем скобки: print STDOUT 2 + 2 * 25 / 4, ' ', 16 . '$'; # Напечатает '14.5 16$' # Теперь каждый элемент списка после вычисления # передается списковой операции, каждый в скалярном контексте. </source> Так как в Perl типизация динамическая<ref>Другими словами, все операции в Perl изначально перегружены.</ref>, понятие контекста операции является аналогом операции ''приведения типов данных'', которая есть в типизированных языках программирования. В большинстве ситуаций Perl знает лучше, в каком контексте вызывать операцию, но иногда приходится ему помогать, используя синтаксические конструкции и специальные функции. Умение предсказывать, в каком контексте выполнится операция в выражении, позволяет программисту Perl придумывать подчас очень запутанные (но с другой стороны короткие) конструкции, которые не могут себе позволить другие языки программирования из-за типизации. Мы рассмотрим некоторые случаи ниже. <source lang="perl"> # В простом случае левый операнд задает контекст операции. @arr = ("apple", "pear", "grapes", "banana"); # Левый операнд скаляр, а значит присваивание работает в скалярном контексте. # В скалярном контексте массивы в правом операнде приводятся к их размеру. $scalar = @arr; print "$scalar\n"; # Левый операнд список скаляров, а значит присваивание работает в списковом контексте. # В списковом контексте присваивание будет копировать элементы из массива в правом операнде # поэлементно в список в левом операнде. При этом список слева не должен превышать размера массива. ( $element1, $element2, $element3 ) = @arr; print $element1 . " $element2" . " $element3\n"; # Если слева будет переменная на массив, операция также будет в списковом контексте, # и правый массив переопределит значение переменной. @arr1 = (1..4); @arr1 = @arr; print "@arr1\n"; #------------------------------------------------------------------------------------------------------- # Операция print всегда работает в списковом контексте и все элементы списка пытается интерпретировать # как строки. # В стандартной библиотеке Perl есть функция localtime, которая в списковом контексте возвращает # список из 9 элементов, кодирующих текущую дату. print localtime; print "\n"; # Выведет примерно такое: 3219121301251120 # Однако, localtime умеет работать в скалярном контексте, в котором выводит дату в формате текущей локали, # но этот контекст не может использоваться по умолчанию, так как компилятор только знает о том, что # print умеет работать в списковом контексте. # # Этот тот случай, когда мы можем подсказать компилятору выполнить localtime в скалярном контексте, # чтобы напечатать дату в читаемой форме. Для этого нужно воспользоваться функцией scalar, которая # принуждает интерпретировать выражение в своем аргументе исключительно в скалярном контексте. print scalar localtime; print "\n"; # В локали LANG_EN будет печататься в формате "Mon Jan 13 12:32:17 2025". # Можно поступить проще и привести компилятор к скалярному контексту через другую операцию, которая # этот контекст использует. Например, операция конкатенации строк всегда работает в скалярном контексте. # Если компилятор увидит выражение, использующее скалярный контекст, он будет использоваться для всех # операндов операции. Таким образом, такого же результата мы добиваемся, если напишем так: print localtime . "\n"; # "Mon Jan 13 12:32:17 2025" #------------------------------------------------------------------------------------------------------- # Рассмотрим более сложный пример. # Пусть дана такая строка: $word = "111example222"; # Вопрос: как посчитать в ней количество символов цифр и букв и совместить это с печатью в одном компактном выражении? # Для ответа на вопрос "сколько символов данного класса?" здесь следует использовать регулярные выражения. # Так как о регулярных выражениях мы будем говорить много позже, возьмите на веру, что регулярное выражение для # поиска цифр выглядит так '/\d/g', а букв так '/[^\d\s]/g'. # # Примечание: '/[^\d\s]/g' не учитывает Unicode символы. # # Проблема кроется в том, что регулярные выражения умеют работать и в скалярном, и в списковом контекстах. # Конкретно нам нужен списковый контекст, в котором операция возвращает массив совпадений по шаблону, который # мы могли бы преобразовать в размер, тем самым ответив на вопрос "сколько?". Но как нам сказать, чтобы операция # выполнялась в списковом контексте, а не скалярном, ведь специальной функции типа scalar для этого нет? # # Единственный способ сделать это, привести компилятор к этому контексту через другую операцию. # Существует два распространенных приёма провоцировать списковый контекст: # * Можно использовать операцию присваивания, в которой левый операнд это пустой массив. # * Можно использовать операцию разыменовывания ссылки, которая будет работать в контексте типа # разыменовывания. # Ниже мы в одном выражении используем оба приема для демонстрационных целей print "Number of letters: " . ( () = $word =~ /[a-zA-Z]/g ) . "\n" . "Number of digits: " . ( @{ [ $word =~ /\d/g ] } ) . "\n" ; # Number of letters: 7 # Number of digits: 6 </source> Не расстраивайтесь, если вы ничего из предыдущих примеров не поняли, так как мы сильно забегаем в них вперед. Эти примеры призваны показать, как сильно выражения завязаны на контекст операции. Скалярный контекст также можно разделить по типу хранимых данных на ''числовой'', ''строковый'' и ''безразличный''. Perl неспособен заранее распознать этот контекст, поэтому он просто подключает механизм неявного приведения данных, когда скаляры в операндах хранят разные типы. Еще один специальный скалярный контекст — ''булевый''. Так как в Perl нет булева <code>true</code> или <code>false</code>, Perl анализирует строки и числа в булевом контексте, как это было описано выше: <code>0</code>, <code>"0"</code>, <code>"00"</code>, <code>"0.0"</code> и <code>""</code> это условно ЛОЖЬ, а все остальное ИСТИНА. Еще одним контекстом является void-контекст, который используется, когда в выражении нет побочных эффектов. Так, вы можете спокойно писать в Perl такие бессмысленные конструкции (они выполняются в void-контексте): <source lang="perl"> (1,2,3); $n; "Hello"; </source> Этот контекст можно обнаружить, если интерпретатор Perl запущен в режиме вывода предупреждающих сообщений. Еще один контекст это ''подстановочный контекст'', в котором вычисляются операции заключения в кавычки (кроме одинарных кавычек). В этом контексте подставляются переменные и интерпретируются управляющие последовательности. Ниже для справки представлены приоритеты операций. {|class="wikitable" style="width:100%;" |- ! Приоритет ! Операция ! Сочетаемость |- |style="width:10%;"|1 |Вычисление термов и левосторонних списковых операций |style="width:20%;"|Слева направо |- |2 |<code><nowiki>-></nowiki></code> |Слева направо |- |3 |<code><nowiki>++</nowiki></code> <code><nowiki>--</nowiki></code> |Не сочетаются |- |4 |<code><nowiki>**</nowiki></code> |Справа налево |- |5 |<code><nowiki>!</nowiki></code> <code><nowiki>~</nowiki></code> <code><nowiki>\</nowiki></code> унарный <code><nowiki>+</nowiki></code> унарный <code><nowiki>-</nowiki></code> |Справа налево |- |6 |<code><nowiki>=~</nowiki></code> <code><nowiki>!=</nowiki></code> |Слева направо |- |7 |<code><nowiki>*</nowiki></code> <code><nowiki>/</nowiki></code> <code><nowiki>%</nowiki></code> <code><nowiki>x</nowiki></code> |Слева направо |- |8 |<code><nowiki>+</nowiki></code> <code><nowiki>-</nowiki></code> <code><nowiki>.</nowiki></code> |Слева направо |- |9 |<code><nowiki><<</nowiki></code> <code><nowiki>>></nowiki></code> |Слева направо |- |10 |Именованные унарные операции |Не сочетаются |- |11 |<code><nowiki><</nowiki></code> <code><nowiki>></nowiki></code> <code><nowiki><=</nowiki></code> <code><nowiki>>=</nowiki></code> <code><nowiki>lt</nowiki></code> <code><nowiki>gt</nowiki></code> <code><nowiki>le</nowiki></code> <code><nowiki>ge</nowiki></code> |Не сочетаются |- |12 |<code><nowiki>==</nowiki></code> <code><nowiki>!=</nowiki></code> <code><nowiki><=></nowiki></code> <code><nowiki>eq</nowiki></code> <code><nowiki>ne</nowiki></code> <code><nowiki>cmp</nowiki></code> |Не сочетаются |- |13 |<code><nowiki>&</nowiki></code> |Слева направо |- |14 |<code><nowiki>|</nowiki></code> <code><nowiki>^</nowiki></code> |Слева направо |- |15 |<code><nowiki>&&</nowiki></code> |Слева направо |- |16 |<code><nowiki>||</nowiki></code> |Слева направо |- |17 |<code><nowiki>..</nowiki></code> <code><nowiki>...</nowiki></code> |Не сочетаются |- |18 |<code><nowiki>?:</nowiki></code> |Справа налево |- |19 |<code><nowiki>=</nowiki></code> <code><nowiki>**=</nowiki></code> <code><nowiki>+=</nowiki></code> <code><nowiki>-=</nowiki></code> <code><nowiki>.=</nowiki></code> <code><nowiki>*=</nowiki></code> <code><nowiki>/=</nowiki></code> <code><nowiki>%=</nowiki></code> <code><nowiki>x=</nowiki></code> <code><nowiki>&=</nowiki></code> <code><nowiki>|=</nowiki></code> <code><nowiki>^=</nowiki></code> <code><nowiki><<=</nowiki></code> <code><nowiki>>>=</nowiki></code> <code><nowiki>&&=</nowiki></code> <code><nowiki>||=</nowiki></code> |Справа налево |- |20 |<code><nowiki>,</nowiki></code> <code><nowiki>=></nowiki></code> |Слева направо |- |21 |Правосторонние списковые операции |Не сочетаются |- |22 |<code><nowiki>not</nowiki></code> |Справа налево |- |23 |<code><nowiki>and</nowiki></code> |Слева направо |- |24 |<code><nowiki>or</nowiki></code> <code><nowiki>xor</nowiki></code> |Слева направо |} * В данной таблице чем выше приоритет операции и чем левее она стоит (в большинстве случаев), тем раньше она выполняется. * Приоритет списковой операции зависит от ее места в выражении и может изменяться от наивысшего к наименьшему. Все операции в выражении, стоящие слева от списковой, имеют наивысший приоритет по отношению к ней (смотрите 21 приоритет). * Свойство сочетаемости означает, что операции одного приоритета могут быть в одном выражении, причем порядок их разрешения может быть слева направо или справа налево. * Скобки позволяют изменить порядок вычисления, определяемому в обычных условиях приоритетом и сочетаемостью. Скобки всегда наделяют выражение в них наивысшим приоритетом. == Примечания == {{примечания}} bswgao7dtln23le5wpbydy9cxstxmsp Рецепт:Мандрыки 104 35854 269870 2026-08-26T14:20:58Z Heffalump1974 37550 Заготовка, к уточнению деталей 269870 wikitext text/x-wiki {{Рецепт |Категория = Выпечка |Порций = |Время = |Сложность = |Энергетическая ценность = |Изображение = Mandrykas.jpg }} '''Мандры́ки''' — коржики с открытой или закрытой начинкой, как сладкой, так и несладкой. == Мандрыки 1 <ref name="ukrstravy1960" /> == ([[Кулинарная книга/Источники/Украинские блюда (1960)|Украинские блюда]]) <div class="mw-collapsible"> {{Начало цитаты|источник=Українські страви, 1960, с. 343}} '''Мандрыки с вишнями.''' Всыпают в кастрюлю 2 стакана муки, вливают туда 1 стакан теплого молока и размешивают. Разведенные отдельно в 1 ст. ложке теплого молока дрожжи размешивают и ставят в теплое место. Когда тесто подойдет, в него кладут 1—2 яйца, соль и вымешивают, добавляя муку, пока тесто не начнет отставать от рук и кастрюли. После вымешивания тесто ставят снова в теплое место, чтобы оно подошло. Вишни очищают, посыпают сахарным песком и дают постоять 1 час. После этого с вишен отцеживают сок, прокипятят его и поливают им готовые мандрыки. Когда тесто подойдет, его раскатывают на тонкие лепешки и кладут на них вишни так, чтобы не было свободного места, но чтобы и вишни не лежали одна на другой, посыпают сахаром, защипывают края и ставят в духовку запекаться, накрыв сверху бумагой. Вынув из духовки, посыпают сахаром. Подают на стол с вишневым соком. К мандрыкам можно подавать также сметану. На 3 стакана муки — 1—2 яйца, 2 стакана молока, 15 г дрожжей, 600 г вишен, 200 г сахара. {{Конец цитаты}} {{Начало цитаты|источник=там же, с. 343}} '''Мандрыки с капустой.''' Готовят дрожжевое тесто и, когда оно подойдет, делают лепешки, края которых поднимают и защипывают. Капусту мелко шинкуют, тушат со сливочным маслом, луком, перцем и солью. Когда тесто лепешек подойдет, на них кладут охлажденную капусту, края их смазывают яйцом, а капусту поливают маслом, в котором жарился лук, и ставят в горячую духовку выпекаться. На 2,5 стакана муки — 20 г дрожжей, 0,5 стакана молока, 1—2 яйца, соль, 700 г свежей капусты, 100 г лука, 50 г сливочного масла. {{Конец цитаты}} {{Начало цитаты|источник=там же, с. 343}} '''Мандрыки с творогом.''' Приготовляют бездрожжевое тесто. Творог хорошо отжимают или кладут под гнет, протирают сквозь сито, добавляют сметану, яйца, соль, сахар, растопленное масло и размешивают, чтобы не было комочков. Тесто, хорошо вымесив, раскатывают тонким слоем, вырезают кружки, сверху кладут подготовленный творог, защипывают края, укладывают на смазанный жиром и посыпанный мукой противень, смазывают яйцом и выпекают в духовке. На 4 стакана муки — 200 г сметаны, 200 г масла, 3 яйца, 800 г творога, по 1 ст. ложке сахара и вершкового масла, 1 чайную ложку соли. {{Конец цитаты}} {{Начало цитаты|источник=там же, с. 344}} '''Мандрыки с вареньем.''' Муку просеивают на разделочную доску, делают в ней углубление, в которое кладут яйца, растертые вареные желтки, вершковое масло, сахар, сметану, соль и быстро замешивают тесто. Тесто кладут на тарелку, накрывают чистым полотенцем и выносят в холодное место на 30—40 минут. После этого тесто раскатывают тонким слоем (толщиной 0,5 см), вырезают стаканом или специальной выемкой кружки. На кружки накладывают равным слоем ягоды из варенья, а край кружка заворачивают зигзагообразно внутрь. Если ягоды берут свежие, то их предварительно тушат, сливают с них образовавшийся сок и добавляют по вкусу сахар. Мандрыки укладывают на смазанный противень и ставят в духовку на 10—15 минут для выпекания. На 3 стакана муки — 0,5 стакана сметаны, 100 г вершкового масла, 2 яйца, 2 вареных желтка, 2 ст. ложки сахара, 0,5 чайной ложки соли. {{Конец цитаты}} {{Начало цитаты|источник=там же, с. 344}} '''Мандрыки со сливами.''' Тесто приготовляют так же, как и для мандрыков с вареньем. Сливы очищают от косточек, слегка отваривают с сахаром, а сироп сцеживают. Сливы укладывают на лепешки плотным слоем в один ряд, посыпают сахаром, заворачивают края внутрь, смазывают яйцом, укладывают на смазанный противень и выпекают в духовке в течение 15—20 минут. Выпеченные мандрыки посыпают сахаром и подают на стол со сметаной или сахарной пудрой, которые подают отдельно. На 4 стакана муки — 200 г масла, 200 г сахара, 2 яйца, 2 ст. ложки сметаны, 500 г слив, 200 г сахарной пудры. {{Конец цитаты}} {{Начало цитаты|источник=там же, с. 344}} '''Мандрыки с клубникой или малиной.''' Тесто приготовляют, как и для мандрыков с вареньем. Клубнику слегка отваривают с сахаром и отцеживают сироп. Подготовленную клубнику кладут на раскатанную лепешку ровным слоем, края лепешки заворачивают зигзагообразно внутрь, посыпают сверху сахаром, укладывают на смазанный противень и выпекают в духовке. На 4 стакана муки — 200 г сахара, 200 г сливочного масла, 2 яйца, 2 ст. ложки сметаны, 200 г сахарной пудры, 800 г клубники. {{Конец цитаты}} </div> == Примечания == {{примечания|refs= <ref name="ukrstravy1960">{{Книга |ответственный= Л.П. Денисенко |заглавие = Українські страви |часть = Мандрики з вишнями, Мандрики з капустою, Мандрики з сиром, Мандрики з варенням, Мандрики із сливами, Мандрики з полуницями або малиною. |место = К. |издательство = Державне видавництво технічної літератури України |год = 1960 |страницы = |страниц = 452 с., ил. }}</ref> }} == Ссылки == * [[w:Мандрыки (блюдо)|Статья в Википедии «Мандрыки (блюдо)»]] == Примечания == <references /> {{Украинская кухня}} [[Категория:Рецепты]] [[Категория:Украинская кухня]] 8tgvxdysuvr4mr6jsk7khwxn6xf6p1w