Не удается получить доступ к файлу pascal abc
Обновлено: 21.11.2024
Выполняет поиск совпадений с шаблоном и заменяет их заменой .
Параметры
Шаблон для поиска. Это может быть строка или массив строк.
Также доступны несколько модификаторов PCRE.
Строка или массив строк для замены. Если этот параметр является строкой, а параметр шаблона — массивом, все шаблоны будут заменены этой строкой. Если и шаблон, и параметры замены являются массивами, каждый шаблон будет заменен замещающим аналогом. Если в массиве замещения меньше элементов, чем в массиве шаблонов, все лишние шаблоны будут заменены пустой строкой.
замена может содержать ссылки в форме \ n или $ n , последняя форма является предпочтительной. Каждая такая ссылка будет заменена текстом, захваченным n-м шаблоном в скобках. n может принимать значения от 0 до 99, а \0 или $0 относятся к тексту, совпадающему со всем шаблоном. Открывающие скобки считаются слева направо (начиная с 1), чтобы получить номер захватываемого подшаблона. Обратите внимание, что обратную косую черту в строковых литералах может потребоваться экранировать.
При работе с замещающим шаблоном, когда за обратной ссылкой сразу же следует другое число (т. е. при размещении буквального числа сразу после совпавшего шаблона), вы не можете использовать знакомую запись \1 для своей обратной ссылки. \11 , например, может запутать preg_replace() , так как он не знает, хотите ли вы, чтобы обратная ссылка \1 следовала за литералом 1 , или обратная ссылка \11 сопровождалась ничем. В этом случае решение состоит в том, чтобы использовать $1. Это создает изолированную обратную ссылку $1, оставляя 1 литералом.
При использовании устаревшего модификатора e эта функция экранирует некоторые символы (а именно ' , " , \ и NULL) в строках, заменяющих обратные ссылки. Это делается для того, чтобы гарантировать отсутствие синтаксических ошибок при использовании обратных ссылок с одинарными или двойные кавычки (например, 'strlen(\'$1\')+strlen("$2")' ). Убедитесь, что вы знакомы с синтаксисом строк PHP, чтобы точно знать, как будет выглядеть интерпретируемая строка.
Строка или массив строк для поиска и замены.
Если subject является массивом, то поиск и замена выполняются для каждой записи subject , а возвращаемое значение также является массивом.
Максимально возможные замены для каждого шаблона в каждой строке темы. По умолчанию -1 (без ограничений).
Если указано, эта переменная будет заполнена количеством выполненных замен.
Возвращаемые значения
preg_replace() возвращает массив, если параметр темы является массивом, или строку в противном случае.
Если найдены совпадения, будет возвращена новая тема, в противном случае тема будет возвращена без изменений или null, если произошла ошибка.
Ошибки/Исключения
Использование модификатора "\e" является ошибкой; в этом случае выдается E_WARNING.
Если переданный шаблон регулярного выражения не компилируется в допустимое регулярное выражение, выдается E_WARNING.
Примеры
$string = '15 апреля 2003 г.';
$pattern = '/(\w+) (\d+), (\d+)/i' ;
$replacement = '$1,$3' ;
echo preg_replace ($pattern, $replacement, $string);
?>?php
Приведенный выше пример выведет:
$string = 'Быстрая коричневая лиса перепрыгивает через ленивую собаку.' ;
$patterns = array();
$patterns [ 0 ] = '/quick/' ;
$patterns [ 1 ] = '/brown/' ;
$patterns [ 2 ] = '/fox/' ;
$replacements = array();
$replacements [ 2 ] = 'медведь' ;
$replacements [ 1 ] = 'черный' ;
$replacements [0] = 'slow';
echo preg_replace ($patterns, $replacements, $string);
?>?php
Приведенный выше пример выведет:
Сортируя шаблоны и замены, мы должны получить то, что хотели.
ksort ( $patterns );
ksort ($replacements);
echo preg_replace ($patterns, $replacements, $string);
?>?php
Приведенный выше пример выведет:
Приведенный выше пример выведет:
В этом примере из строки удаляются лишние пробелы.
$str = 'foo o' ;
$str = preg_replace ( '/\s\s+/' , ' ' , $str );
// Теперь это будет 'foo o'
echo $str ;
?>?php
echo preg_replace (array('/\d/', '/\s/'), '*', 'xp 4 to', - 1, $count);
echo $count; //3
?>
Приведенный выше пример выведет:
Примечания
Примечание:
При использовании массивов с шаблоном и заменой ключи обрабатываются в том порядке, в котором они появляются в массиве. Это не обязательно то же самое, что и порядок числового индекса. Если вы используете индексы, чтобы определить, какой шаблон какой заменой должен быть заменен, вы должны выполнить ksort() для каждого массива перед вызовом preg_replace().
См. также
Добавленные пользователем заметки 50 заметок
Потому что я много ищу 4 это:
Следующее следует экранировать, если вы пытаетесь сопоставить этот символ
Определения специальных символов
\ Заключить в кавычки следующий метасимвол
^ Соответствует началу строки
. Совпадает с любым символом (кроме новой строки)
$ Совпадает с концом строки (или перед новой строкой в конце)
| Чередование
() Группировка
[] Класс символов
* Совпадение 0 или более раз
+ Совпадение 1 или более раз
? Совпадение 1 или 0 раз
Совпадение ровно n раз
Совпадение не менее n раз
Совпадение не менее n, но не более m раз
Больше специальных символов
\t табуляция (HT, TAB)
\n новая строка (LF, NL)
\r возврат (CR)
\f перевод страницы (FF)
\авария (звонок) ( BEL)
\e escape (например, troff) (ESC)
\033 восьмеричный символ (например, PDP-11)
\x1B hex char
\c[ контрольный символ< br />\l следующий символ в нижнем регистре (например, vi)
\u следующий символ в верхнем регистре (например, vi)
\L нижний регистр до \E (например, vi)
\U верхний регистр до \E ( think vi)
\E модификация в конце регистра (think vi)
\Q заключает в кавычки (отключает) метасимволы шаблона до \E
Еще больше специальных символов
\w Соответствует «слову» (буквенно-цифровой плюс "_")
\W Совпадение с символом, не являющимся словом
\s Совпадение с пробельным символом
\S Совпадение с непробельным символом
\d Совпадение с a цифровой символ
\D Совпадение с нецифровым символом
\b Совпадение с границей слова
\B Совпадение с не-(границей слова)
\A Совпадение только в начало строки
\Z Совпадение только в конце строки или перед новой строкой в конце
\z Совпадение только с концом строки
\G Совпадение только там, где предыдущая m//g закончилась (работает только с /g)
Генератор постов для создания чистых URL-адресов из заголовков.
Он работает со многими языками.
function remove_accent ($str)
<
$a = array( 'А', 'А', 'А', 'А', 'А', 'А', 'А' , «С», «Э», «Э», «К», «Н», «М», «Н», «О», «П», «Р», «С», «Т», « Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'Ù', 'U', 'Û', 'U', 'Ý', 'ß', 'а', 'а' , 'а', 'а', 'а', 'р', 'а', 'з', 'э', 'э', 'э', 'э', 'м', 'т', ' î', 'ï', 'с', 'т', 'у', 'т', 'х', 'о', 'о', 'у', 'у', 'у', 'ю' , 'ý' , 'ÿ' , 'А' , 'а' , 'А' , 'А' , 'А' , 'А' , 'Э' , 'Ч' , 'Э' , 'Э' , ' Ċ', 'ċ', 'Č', 'č', 'Ď', 'ď', 'Đ', 'đ', 'E', 'E', 'Ĕ', 'ĕ', 'E' , 'Э' , 'К' , 'Э' , 'К' , 'Э' , 'М' , 'Г' , 'Г' , 'Г' , 'Г' , 'Г' , 'Г' , ' ģ', 'Ĥ', 'ĥ', 'Ħ', 'ħ', 'Ĩ', 'ĩ', 'Ī', 'i', 'Ĭ', 'ĭ', 'Į', 'i' , 'İ', 'ı', 'IJ', 'ij', 'Ĵ', 'ĵ', 'Ķ', 'ķ', 'Ĺ', 'ĺ', 'Ļ', 'ļ', ' Ľ, ľ, Ŀ, ŀ, Ł, ł, Ń, ń, Ņ, ņ, Ň, ň, ʼn , "Ō", "ō", "Ŏ", "ŏ", "Ő", "ő", "Œ", "œ", "Ŕ", "ŕ", "Ŗ", "ŗ", " Ř", "ř", "Ś", "ś", "Ŝ", "ŝ", "Ş", "ş", "Š", "š", "Ţ", "ţ", " Ť', 'ť', 'Ŧ', 'ŧ', 'Ũ', 'ũ', 'U', 'ū', 'Ŭ', 'ŭ', 'Ů', 'ů', 'Ű' , "ű", "Ų", "ų", "Ŵ", "ŵ", "Ŷ", "ŷ", "Ÿ", "Ź", "ź", "Ż", "ż", " Ž', 'ž', 'ſ', 'ƒ', 'Ơ', 'ơ', 'Ư', 'ư', 'Ǎ', 'ǎ', 'Ǐ', 'ǐ', 'Ǒ' , 'ǒ' , 'Ǔ' , 'ǔ' , 'Ǖ' , 'ǖ' , 'Ǘ' , 'ǘ' , 'Ǚ' , 'ǚ' , 'Ǜ' , 'ǜ' , 'Ǻ' , ' ǻ', 'Ǽ', 'ǽ', 'Ǿ', 'ǿ');
$b = array('A', 'A', 'A', 'A', 'A', 'A', 'AE', 'C', 'E', 'E', ' Е', 'Е', 'И', 'И', 'И', 'И', 'Д', 'Н', 'О', 'О', 'О', 'О', 'О' , «О», «У», «У», «У», «У», «У», «с», «а», «а», «а», «а», «а», «а». а', 'ае', 'с', 'е', 'е', 'е', 'е', 'и', 'и', 'и', 'и', 'н', 'о' , 'о', 'о', 'о', 'о', 'о', 'у', 'у', 'у', 'у', 'у', 'у', 'А', ' а', 'А', 'а', 'А', 'а', 'С', 'с', 'С', 'с', 'С', 'с', 'С', 'с' , 'D' , 'd' , 'D' , 'd' , 'E' , 'e' , 'E' , 'e' , 'E' , 'e' , 'E' , 'e' , ' E', 'e', 'G', 'g', 'G', 'g', 'G', 'g', 'G', 'g', 'H', 'h', 'H' , 'ч', 'я', 'я', 'я', 'я', 'я', 'я', 'я', 'я', 'я', 'и', 'ж', ' ij', 'J', 'j', 'K', 'k', 'L', 'l', 'L', 'l', 'L', 'l', 'L', 'l' , 'л', 'л', 'Н', 'н', 'Н', 'н', 'Н', 'н', 'н', 'О', 'о', 'О', ' o', 'O', 'o', 'OE', 'oe', 'R', 'r', 'R', 'r', 'R', 'r', 'S', 's' , 'С', 'с', 'С', 'с', 'С', 'с', 'Т', 'т', 'Т', 'т', 'Т', 'т', ' У', 'у', 'У' , «у», «у», «у», «у», «у», «у», «у», «у», «у», «у», «у», «у», «у». y', 'Y', 'Z', 'z', 'Z', 'z', 'Z', 'z', 's', 'f', 'O', 'o', 'U' , 'у', 'А', 'а', 'я', 'и', 'о', 'о', 'у', 'у', 'у', 'у', 'у', ' u', 'U', 'u', 'U', 'u', 'A', 'a', 'AE', 'ae', 'O', 'o');
вернуть str_replace ( $a , $b , $str );
>
Если вы хотите поймать символы, а также европейские, русские, китайские, японские, корейские и т. д., просто :
- используйте mb_internal_encoding('UTF-8');
- используйте preg_replace(' `. `u', '. ', $string) с модификатором u (юникод)
Обратите внимание, что строка замены, использующая нотацию $
$replacement = '$1,$3'; // Правильно - в одинарных кавычках
$replacement = "$1,$3"; // Неверно — в двойных кавычках
$replacement = "$1 one , $3"; // Правильно — в двойных кавычках, но с нотацией $n.
Это может незаметно для вас, потому что использование "$" не является ошибкой.Двойные кавычки позволяют использовать строку, содержащую интерполяцию переменных, а фигурные скобки делают переменную PHP «переменной-переменной». В приведенном выше примере неопределенный $ будет оцениваться как NULL, а не замененная строка. Действительный PHP, но не то, что вы хотели.
Обратите внимание, что при задании аргументов массива замена происходит последовательно:
$p = массив('/a/', '/b/', '/c/');
$r = массив('b', 'c', 'd');
print_r (preg_replace ($p, $r, 'a'));
// => д
?>
$c = "2 4 8" ;
эхо ($c); // отображение: 2 4 8
$cp = "/(\d)\s(\d)\s(\d)/e" ; //шаблон
$cr = "'\\3*\\2+\\1='.(('\\3')*('\\2')+('\\1') )"; //замена
$c = preg_replace ($cp, $cr, $c);
эхо ($c); //дисплей:8*4+2=34
?>
preg_replace (и другие preg-функции) возвращают null вместо строки при возникновении проблем, о которых вы, вероятно, не думали!
------------------- ------
При работе с HTML-документами и их анализе случаются случаи, когда вы сталкиваетесь с документами длиной более 100 000 символов, что может привести к сбою некоторых регулярных выражений из-за ограничения обратного отслеживания, указанного выше.
Поскольку необработанное возвращаемое значение NULL обычно создает последовательную ошибку в приложении с нежелательными и непредвиденными последствиями, я нашел следующее решение весьма полезным и, по крайней мере, спасло приложение от сбоя:
$string_after = preg_replace ('/some_regexp/', "replacement", $string_before);
// если произошла ошибка продолжаем работать с неизменной исходной строкой
if ( PREG_NO_ERROR !== preg_last_error ())
$string_after = $string_before ;
// поместите сюда email-отправку или лог-сообщение
> //if
// освобождаем память
unset( $string_before );
?>
Вы также можете или должны поместить сообщение журнала или отправку электронного письма в условие if, чтобы получать информацию, когда одно из ваших регулярных выражений не работает. получить желаемый эффект.
Если вы хотите заменить только n-е вхождение $pattern, вы можете использовать эту функцию:
функция preg_replace_nth ($pattern, $replacement, $subject, $nth = 1) return preg_replace_callback ($pattern,
функция($found) use (& $pattern, & $replacement, & $nth) $ nth --;
if ($nth == 0) вернуть preg_replace ($pattern, $replacement, reset ($found));
вернуть reset ($found);
>, $ тема , $nth );
>
echo preg_replace_nth( "/(\w+)\|/" , '$ - 4-й|' , "|aa|b|cc|dd|e|ff|gg|kkk|" , 4 ); р>
?>
это выводит |aa|b|cc|dd является 4-м|e|ff|gg|kkk|
обратные ссылки принимаются в $replacement
Обратите внимание, что в большинстве случаев гораздо эффективнее использовать preg_replace_callback() с именованной функцией или анонимной функцией, созданной с помощью create_function(), вместо модификатора /e. Когда preg_replace() вызывается с модификатором /e, интерпретатор должен разобрать строку замены в код PHP один раз для каждой сделанной замены, в то время как preg_replace_callback() использует функцию, которую нужно разобрать только один раз.
Может быть полезно отметить, что если вы передаете ассоциативный массив в качестве параметра $replacement, ключи сохраняются.
$replaced = preg_replace ('/foo/', 'bar', ['first' => 'foobar', 'second' => 'barfoo']);
// $replaced теперь ['first' => 'barbar', 'second' => 'barbar'].
?>
Потратил несколько часов из-за этого:
Причина в том, что code2utf будет вызываться с начальным нулем, что соответствует шаблону - code2utf(039).
И это имеет значение! PHP обрабатывает 039 как восьмеричное число.
Попробуйте
Решение:
Кажется, существует некоторая путаница в том, как работает жадность. Для тех, кто знаком с регулярными выражениями в других языках, особенно в Perl: это работает так, как вы ожидаете, и как задокументировано. Жадный по умолчанию, нежадный, если вы ставите квантификатор со знаком вопроса.
Чтобы было понятно, несколько примеров:
$preview = "куча всего вот это
и еще много всего со вторым кодовым блоком
и дополнительным в конце" ;
$preview_default = preg_replace ('/(.*)/is', ", $preview);
$preview_manually_ungreedy = preg_replace ('/(.*?)/is', ", $preview);
$preview_U_default = preg_replace ('/(.*)/isU', ", $preview);
$preview_U_manually_greedy = preg_replace ('/(.*?)/isU', ", $preview);
echo "По умолчанию, нет ?: $preview_default \n" ;
echo "По умолчанию, с ?: $preview_manually_ungreedy \n" ;
echo "U флаг, нет ?: $preview_U_default \n" ;
echo "Флаг U с ?: $preview_U_manually_greedy \n" ;
По умолчанию, нет ?: куча элементов это то
и многое другое со вторым кодовым блоком
, затем дополнительное в конце
По умолчанию с ?: куча вещей это то
и еще много вещей со вторым кодовым блоком
и еще что-то в конце
флаг U, нет ?: куча вещей это то
и многое другое со вторым кодовым блоком
, затем дополнительное в конце
флаг U с ?: куча вещей этот
и многое другое со вторым кодовым блоком
и дополнительным в конце
Как и ожидалось: жадный по умолчанию, ? инвертирует его в нежадный. С флагом U, не жадным по умолчанию, ? делает его жадным.
Предупреждение: распространенной ошибкой при попытке удалить из строки все символы, кроме цифр и букв, является использование кода с регулярным выражением, подобным preg_replace('[^A-Za-z0-9_]', '', . ). Вывод идет в неожиданном направлении, если ваш ввод содержит две двойные кавычки.
echo preg_replace('[^A-Za-z0-9_]', '', 'D"usseldorfer H"auptstrasse')
Важно не забывать о косой черте в начале регулярного выражения:
echo preg_replace('/[^A-Za-z0-9_]/', '', 'D"usseldorfer H"auptstrasse')
PS Альтернативой является использование preg_replace('/\W/', '', $t) для сохранения всех буквенно-цифровых символов, включая символы подчеркивания.
Многие из нас писали программы на языке Pascal задолго до того, как в моду вошли графические пользовательские интерфейсы (GUI) и интегрированные среды разработки (IDE). Многие другие являются новичками в программировании на Паскале, и им необходимо опробовать основные инструменты языка. Третьим приходится писать консольные или текстовые приложения для выполнения сложных задач управления системой.
Программирование в консольном режиме без Lazarus
Несмотря на то, что многие предпочитают использовать Lazarus IDE для написания программ в консольном режиме, вы также можете написать их в любом текстовом редакторе и скомпилировать самостоятельно, вызвав компилятор FPC, например это для программы в example.pas:
Кроме того, доступен текстовый режим fp IDE (немного напоминает старый Turbo Pascal). В следующих разделах мы сосредоточимся на программировании с помощью Lazarus.
Программирование в консольном режиме с помощью Lazarus
Lazarus обеспечивает идеальную среду для изучения Pascal и разработки программ в текстовом режиме. Можно использовать все функции интегрированной среды разработки, включая редактор исходного кода с подсветкой синтаксиса, доступ к библиотекам, сложные инструменты поиска и завершения кода, а также проверку синтаксиса. Если вам не нужна форма с ее визуальными компонентами, она вам не нужна, но редактор исходного кода Lazarus по-прежнему является отличной средой для разработки программ. Вы можете скомпилировать и запустить свою программу во время разработки, не выходя из редактора.
Чтобы запустить программу в режиме консоли, перейдите в Главное меню и выберите «Проект» -> «Новый проект», а затем выберите «Программа» или «Консольное приложение». Среда IDE не будет генерировать все дополнительные файлы, связанные с полноценным графическим приложением, и не будет открывать окно инспектора объектов, а откроет редактор исходного кода со скелетной структурой программы и будет ожидать вашего ввода при программировании.
Примечание. В Windows приложение с графическим интерфейсом не имеет консоли и поэтому не может писать или читать. Вы получите сообщение об ошибке Файл не открыт. Отключите в разделе Параметры проекта/Параметры компилятора/Связывание/Целевые параметры/Приложение Win32 GUI, чтобы создать консольное приложение. В Lazarus IDE 1.4 это находится в разделе Проект (меню)/Параметры проекта/Параметры компилятора/Конфигурация и цель/Специфические параметры цели/Приложение Win32 GUI.
Примечание. В Lazarus есть некоторые функции для программ командной строки, например для копирования файлов. Чтобы использовать их, добавьте требование проекта для LazUtils, которое не будет использовать весь LCL. Затем добавьте соответствующую единицу в предложение использования.
Тип проекта: Консольное приложение
При выборе этого типа проекта в Lazarus создается программа с новым классом, производным от TCustomApplication. TCustomApplication предоставляет много общего и упрощает программирование утилит командной строки. Например, проверка параметров командной строки, написание справки, проверка переменных среды и обработка исключений. Все программы LCL используют это автоматически.
Тип проекта: Программа
В качестве демонстрации мы напишем очень минималистическую программу на Паскале. В IDE выберите тип проекта «Программа» и пусть IDE вам немного поможет. Например, когда вы добавляете еще один модуль, IDE автоматически добавит имя модуля в раздел использования программы. Это поведение определяется в параметрах проекта. Таким образом, вы можете переключаться между «Программой» и «Пользовательской программой» в любое время.
Пример для полных новичков:
Сценарии Pascal
Кроме того, можно писать сценарии, которые динамически компилируются с помощью InstantFPC, кросс-платформенного решения для запуска (небольших) программ Pascal в виде сценариев. Шебанг
позволяет запускать скрипт как отдельную программу.
Примечание. Хотя InstantFPC используется для запуска сценариев Pascal, он использует обычный Object Pascal, а не язык сценариев PascalScript. Таким образом, «PascalScript» и сценарий Pascal — это не одно и то же.
Запуск программы
Скомпилировать
Когда вы закончите свою программу (или фрагмент программы), вы можете скомпилировать и запустить ее, выбрав «Выполнить» -> «Сборка» (или «Быстрая компиляция») в Главном меню или щелкнув значок зеленого треугольника (Выполнить) на панели кнопок. Любые сообщения компилятора (предупреждения, отчеты о ходе выполнения или сообщения об ошибках) будут отображаться в окне сообщений, и, надеюсь, в конечном итоге появится сообщение
'Проект "Project1" успешно создан.:)'.
Но где же программа?
Если вы еще не сохранили программу, IDE поместит ее во временный каталог (например, /tmp в Linux, C:\temp в Windows, см. Параметры среды/Файлы/Каталог для создания тестовых проектов).
Если вы уже сохранили проект, значит, программа была создана в той же директории, где вы сохранили файл project1.lpi.
Запустить в консоли
Вы можете запустить программу, перейдя в окно консоли (терминала), затем с помощью cd перейдите в каталог и введите имя программы. В Unix/Linux, если она находится в текущем каталоге, вам придется начать с ./, так как программа, вероятно, не будет найдена в PATH.
Пример для Linux/Unix, где программа хранится в /tmp:
Однако может быть очень неудобно постоянно переходить из редактора Lazarus в окно терминала и обратно. К счастью, есть механизм, который позволяет открывать окно терминала из среды Lazarus.
Запуск в IDE
Во внутренней консоли: показать в окне вывода терминала.
В перенаправлении вывода.
В главном меню выберите «Выполнить» -> «Параметры запуска», затем установите флажок «Использовать запускаемое приложение». В первый раз, когда вы сделаете это и попробуете последовательность компиляции/запуска, вы, вероятно, получите грубое сообщение:
В этом случае необходимо изменить права доступа к соответствующему файлу (например, с помощью команды chmod +x имя файла или утилиты Windows для изменения разрешений); возможно, вам придется сделать это как root. После этого каждый раз, когда вы запускаете свою программу, будет появляться окно консоли, и в нем будут отображаться все ваши текстовые операции ввода-вывода (readln, writeln и т. д.).
После того, как ваша программа завершит выполнение, на экране появится сообщение "Нажмите Enter". Таким образом, любой вывод, созданный вашей программой, останется на экране до тех пор, пока вы не прочтете его; после того, как вы нажмете «ввод», окно консоли закроется.
К сожалению, этот метод не позволяет использовать встроенный отладчик.
Запуск в IDE с перенаправленным выводом
Если вы хотите увидеть, что записывается в стандартный вывод, а также использовать встроенный отладчик, стандартный вывод можно перенаправить в файл с помощью следующего кода:
Затем файл Output.txt можно просмотреть с помощью команды «tail -f output.txt» или просмотреть в редакторе, если «tail» недоступен в вашей ОС.
В качестве альтернативы можно использовать Lazarus 0.9.31 или более поздней версии (только для Linux): в меню «Вид» в разделе «Отладка Windows» есть запись для «консольного вывода» для просмотра стандартного вывода
Вывод Unicode (UTF8)
Если вы хотите, чтобы программа, работающая в режиме консоли, показывала вывод в формате Unicode (UTF8) в Windows Vista и более поздних версиях (и, возможно, в более ранних версиях), вы можете использовать команду SetConsoleOutputCP, чтобы настроить консоль на набор символов UTF8. р>
Примечание: вам нужно убедиться, что шрифт консоли может отображать буквы, которые вы хотите вывести (например, греческий, кириллица, корейский).
Примечание. Вам потребуется включить модуль Windows.
Подробнее о поддержке Unicode в Lazarus и FPC см. в разделе Поддержка LCL Unicode.
Примеры
Вы можете использовать редактор Lazarus, чтобы опробовать все примеры из стандартных учебников Pascal, или вы можете написать свои собственные. Некоторые из наиболее полезных процедур — это процедуры для выполнения системных команд или запуска других программ (независимо от того, написаны они на Pascal, C или Perl, а также в сценариях оболочки или пакетных сценариях).
Выполнить команду оболочки
Вот пример для Пользовательской программы или Программы. это специфично для Linux/Unix/macOS:
Пример: обновить FPC и Lazarus
Можно выполнять более сложные команды. Например, если вы уже проверили репозитории SVN для FPC и Lazarus (см. buildfaq), вы можете обновлять исходные файлы FPC и Lazarus, извлекая их из репозитория SVN с помощью следующей последовательности вызовов:
Обратите внимание, что ввод команды
не работает, так как после каждого вызова функции fpsystem() выполнение программы возвращается в каталог, в котором оно началось; поэтому нам нужно включать несколько операторов на строку в наши вызовы оболочки через fpsystem(). [Скорее: он всегда начинается в формате . ]
Нет необходимости вводить каждую команду как отдельную строку Паскаля; можно создать такой файл скрипта bash (из buildfaq):
Назовите его updatelaz.sh, а затем вместо использования bash для его непосредственного выполнения вызовите его из программы на языке Pascal следующим образом:
Где базовый тип указывает тип компонентов файла.Базовым типом может быть что угодно, например целое число, вещественное число, логическое значение, перечисление, поддиапазон, запись, массивы и наборы, кроме файлов другого типа. Переменные типа файла создаются с помощью объявления var -
Ниже приведены некоторые примеры определения некоторых типов файлов и файловых переменных.
Создание и запись в файл
Давайте напишем программу, которая создаст файл данных для записей учащихся. Он создаст файл с именем student.dat и запишет в него данные учащегося —
При компиляции и запуске программа создаст файл с именем students.dat в рабочем каталоге. Вы можете открыть файл с помощью текстового редактора, например блокнота, чтобы просмотреть данные Джона Смита.
Чтение из файла
Мы только что создали и записали в файл с именем student.dat. Теперь давайте напишем программу, которая считывала бы данные студента из файла —
Когда приведенный выше код скомпилирован и выполнен, он дает следующий результат —
Файлы как параметр подпрограммы
Pascal позволяет использовать файловые переменные в качестве параметров в стандартных и определяемых пользователем подпрограммах. Следующий пример иллюстрирует эту концепцию. Программа создает файл с именем rainfall.txt и сохраняет некоторые данные об осадках. Затем он открывает файл, считывает данные и вычисляет среднее количество осадков.
Обратите внимание, что если вы используете параметр файла с подпрограммами, он должен быть объявлен как параметр var.
Когда приведенный выше код скомпилирован и выполнен, он дает следующий результат —
Текстовые файлы
Текстовый файл на Паскале состоит из строк символов, каждая строка заканчивается маркером конца строки. Вы можете объявить и определить такие файлы как -
Разница между обычным файлом символов и текстовым файлом заключается в том, что текстовый файл разделен на строки, каждая из которых завершается специальным маркером конца строки, автоматически вставляемым системой. В следующем примере создается и записывается в текстовый файл с именем contact.txt —
Когда приведенный выше код скомпилирован и выполнен, он дает следующий результат —
Добавление к файлу
Добавление к файлу означает запись в существующий файл, в котором уже есть некоторые данные, без перезаписи файла. Следующая программа иллюстрирует это —
Когда приведенный выше код скомпилирован и выполнен, он дает следующий результат —
Функции обработки файлов
Free Pascal предоставляет следующие функции/процедуры для работы с файлами —
процедура Append(var t: Text);
Открывает файл в режиме добавления
процедура Assign(out f: file; const Name:);
Присваивает имя файлу
процедура Assign(out f: file; p: PChar);
Присваивает имя файлу
процедура Assign(out f: file; c: Char);
Присваивает имя файлу
процедура Assign(out f: TypedFile; const Name:);
Присваивает имя файлу
процедура Assign(out f: TypedFile; p: PChar);
Присваивает имя файлу
процедура Assign(out f: TypedFile; c: Char);
Присваивает имя файлу
процедура Assign(out t: Text; const s:);
Присваивает имя файлу
процедура Assign(out t: Text; p: PChar);
Присваивает имя файлу
процедура Assign(out t: Text; c: Char);
Присваивает имя файлу
процедура BlockRead(var f: file; var Buf; count: Int64; var Result: Int64);
Читает данные из файла в память
процедура BlockRead(var f: file; var Buf; count: LongInt; var Result: LongInt);
Читает данные из файла в память
процедура BlockRead(var f: file; var Buf; count: Cardinal; var Result: Cardinal);
Читает данные из файла в память
процедура BlockRead(var f: файл; var Buf; count: Word; var Result: Word);
Читает данные из файла в память
процедура BlockRead(var f: file; var Buf; count: Word; var Result: Integer);
Читает данные из файла в память
процедура BlockRead(var f: file; var Buf; count: Int64);
Читает данные из файла в память
процедура BlockWrite(var f: file; const Buf; Count: Int64; var Result: Int64);
Записывает данные из памяти в файл
процедура BlockWrite(var f: file; const Buf; Count: LongInt; var Result: LongInt);
Записывает данные из памяти в файл
процедура BlockWrite(var f: file; const Buf; Count: Cardinal; var Result: Cardinal);
Записывает данные из памяти в файл
процедура BlockWrite(var f: file; const Buf; Count: Word; var Result: Word);
Записывает данные из памяти в файл
процедура BlockWrite(var f: file; const Buf; Count: Word; var Result: Integer);
На этой странице описаны возможности создания библиотек с помощью Lazarus/FPC и их использования в проектах и пакетах.
Содержание
Связанные темы
Общие
Статическая ссылка
FPC компилирует и связывает статический исполняемый файл по умолчанию. Это означает, что он говорит компоновщику поместить все файлы .o файлы проекта и все пакеты в один большой исполняемый файл.
- Преимущества:
- Нет внешних зависимостей.
- Разные программы на одном компьютере не используют общий код.
- Вы не можете загрузить/выгрузить плагин.
Динамические библиотеки
Альтернативой статической компоновке является использование динамических библиотек. Идея динамических библиотек заключается в совместном использовании кода между программами,
- Преимущества:
- Сохранение кода в памяти
- Сокращение времени запуска часто используемых библиотек
- Разрешение подключаемых модулей.
- Они работают медленнее для редко используемых библиотек.
- Их структура и внутреннее устройство более сложны (в основном это проблема для компилятора).
- Их инициализация отличается (см. ниже)
- Для совместного использования кода требуется, чтобы система версий смешивала только совместимый код.
Операционные системы
Операционная система Динамическое расширение библиотеки Статическое расширение библиотеки Префикс библиотеки FreeBSD .so .a lib macOS< /td> .dylib .a lib Linux .so< /td> .a lib Windows .dll .lib< /td> н/д Haiku .so .a lib Столбцы префикса и расширения библиотеки указывают, как имена библиотек разрешаются и создаются для перечисленных операционных систем.
FreeBSD
macOS
В macOS имя библиотеки всегда будет иметь префикс lib при ее создании. Таким образом, если вы создадите динамическую библиотеку с именем test, результатом будет файл libtest.dylib. При импорте подпрограмм из общих библиотек нет необходимости указывать префикс библиотеки или расширение имени файла библиотеки.
До выпуска FPC 2.2.2 в августе 2008 г. 32-разрядные библиотеки .dylib требовали, чтобы экспортируемые символы начинались с префикса подчеркивания. Это уже не так.
Стандартные расположения для динамических библиотек: ~/lib, /usr/local/lib и /usr/lib. Начиная с macOS 10.15 (Catalina) /usr/lib находится на системном томе только для чтения, поэтому его нельзя использовать для сторонних библиотек. Хотя вы также можете поместить файл .dylib в нестандартное место в вашей файловой системе, вы должны добавить это место в одну из следующих переменных среды:
- LD_LIBRARY_PATH
- DYLD_LIBRARY_PATH
- DYLD_FALLBACK_LIBRARY_PATH
Частные общие библиотеки должны быть включены в пакет приложений вашего приложения. Это особенно важно для библиотек, у которых нет стабильного ABI (например, OpenSSL), так что они привязаны к версии приложения и не могут быть заменены какими-либо другими, даже более новыми версиями, которые могут быть доступны для операционной системы. р>
Дополнительную информацию о macOS см. в разделе «См. также» ниже.
Линукс
Имя файла динамической библиотеки всегда имеет вид 'lib'+имя пакета+'.so'+версия. Например: либз. так . 1 и либз. так . 1.2 . 2 .
Linux ищет библиотеку в следующем порядке:
- сначала в путях переменной среды LD_LIBRARY_PATH
- затем в /lib
- затем /usr/lib
- наконец пути /etc/ld . так . конф
Использование ldconfig после копирования файла библиотеки в каталог lib может решить проблемы с кэшированием.
Чтобы совместно использовать память ( GetMem / FreeMem , строки) с другими библиотеками (не написанными на FPC) под Linux, вы должны использовать модуль cmem. Этот модуль должен быть добавлен самым первым модулем в разделе uses главного исходного файла проекта (обычно .lpr), чтобы его раздел инициализации вызывался до того, как какой-либо другой модуль сможет выделить память.
Окна
Windows ищет библиотеку в:
- сначала в текущем каталоге
- затем системный каталог
- наконец, каталоги, указанные в переменной среды PATH (системный и пользовательский путь).
что делать: не изменилось ли в связи с этим поведение Vista+?
ppumove, .ppu, .ppl
FPC обычно создает для каждого устройства файл .ppu и .o. Файл .ppu содержит всю важную информацию о файле .pas/.pp (типы, требуемые имена файлов, такие как файл .o), а файл .o содержит ассемблерный код и искаженные имена, понятные текущей системе.
Инструмент ppumove, включенный в каждую установку FPC, преобразует один или несколько файлов .ppu и .o в динамическую библиотеку. Это достигается путем вызова компоновщика для сбора всех файлов .o в файл .so (windows: .dll) и удаления ссылок на имена файлов .o из файла .ppu. Эти новые файлы .ppu обычно называются файлами .ppl.
У вас есть выходной каталог пакета (где находятся файлы .ppu):
Это преобразует все файлы .ppu в файлы .ppl и создает libpackagename.so (windows: packagename.dll). Обратите внимание, что в Linux префикс «lib» всегда ставится перед ним.
Эта новая библиотека уже может использоваться другими языками программирования, такими как C. Или программами FPC с использованием внешних модификаторов. Но секции инициализации/финализации должны вызываться автоматически. Это включает инициализацию/финализацию диспетчера кучи. Это означает отсутствие строк или GetMem. Конечно, программисты FPC избалованы, и они могут получить больше.
Внешний — статическая загрузка динамической библиотеки
Статическая загрузка динамической библиотеки может быть выполнена в коде с помощью ключевого слова external, как в приведенном ниже примере, который показывает, как загружается функция gtk:
Loadlibrary — динамическая загрузка динамической библиотеки
Загрузить динамическую библиотеку очень просто с помощью функции Loadlibrary модуля dynlibs.
Основная проблема заключается в том, чтобы получить имя файла, которое зависит от версии и операционной системы. Начиная с версии 2.2.2, для облегчения этого в юните dynlibs объявляется константа «sharedsuffix». Он сопоставляется с соответствующим расширением (dll/so/dylib) без точки в качестве префикса.
Вот функции, объявленные в модуле dynlibs:
SafeLoadLibrary аналогичен LoadLibrary, но также отключает арифметические исключения, которые некоторые библиотеки отключают при загрузке.
Псевдокод использования:
Псевдокод для использования функции с параметрами:
Примечание. До версии 1.9.4 для этого использовалась единица dl. Начиная с версии 1.9.4, dynlibs предоставляет портативную альтернативу. Обратите внимание, что почти любое использование модуля dl, которое не может быть заменено использованием dynlibs, обычно уже непереносимо среди Unices. Уже одно это делает целесообразным максимально возможное использование модульных dynlib.
Упрощенный обзор системы при загрузке общей библиотеки в Linux
На этой диаграмме показано, как настроить разделяемую библиотеку (на которую ссылается ее soname и, по крайней мере, ее настоящее имя) в /etc/ld.so.conf и обновить кэш библиотеки с помощью ldconfig, чтобы сообщить загрузчику системной библиотеки Linux с именем ldd (другие методы загрузки общей библиотеки с переменной среды, такой как LD_LIBRARY_PATH, с кодом, путем включения в двоичный файл elf и т. д. , также показаны на схеме). Для информации часто необходимо проверить, существует ли, по крайней мере, программная символическая ссылка между псевдонимом и настоящим именем. Установка пакетов разработки (файлы *-dev*.deb для установки Debian) всегда предоставляет такую программную символическую ссылку (пример: abc.so), указывающую на soname (пример: abc.so.), на котором выполняется разработка. пакет зависит. Пакеты выпуска иногда забывают об этом, в то время как они лучше всего подходят для извлечения и указания старой установки на новую установленную библиотеку с реальным именем: действительно, общие библиотеки должны уважать приоритет в своих существующих API, функциях, по крайней мере, внутри то же имя пользователя (обратная совместимость).Создание библиотеки
Инициализация
Каждый модуль может содержать раздел инициализации. Порядок разделов инициализации зависит от разделов использования каждого модуля.
Инициализация самой RTL (в system.pp), которая выполняется перед входом в разделы инициализации, немного отличается между программой и общей библиотекой. Наиболее заметно различие в том, как инициализируется обработка исключений:
Обработка исключений
Окна
Сообщалось, что в системах Windows не установлен обработчик исключений для обнаружения аппаратных исключений, таких как нарушения прав доступа или ошибки с плавающей запятой; однако все остальные собственные исключения Pascal, вызванные с помощью Raise, будут работать.
Если вам действительно нужно перехватывать эти аппаратные исключения, вы должны установить свой собственный обработчик, в Windows (начиная с версии XP и выше) это удобно возможно с помощью AddVectoredExceptionHandler() и RemoveVectoredExceptionHandler(), несколько примеров кода приведены в вышеупомянутый отчет об ошибке. Примечание. В FPC 2.7.1/trunk начата работа по решению этой проблемы с использованием 32-битного SEH.
UNIX и UNIX-подобные системы
В UNIX и UNIX-подобных системах (BSD, Darwin, Linux и т. д.) не устанавливается обработчик исключений для перехвата аппаратных исключений (сигналов), таких как нарушения прав доступа в общих библиотеках. Если вы хотите перехватить эти исключения (сигналы) в коде библиотеки, вам необходимо явно вызвать HookSignal ( RTL_SIGDEFAULT ) во время инициализации библиотеки и вызвать UnhookSignal ( RTL_SIGDEFAULT ) во время финализации.
Имейте в виду, что когда вы включаете обработку сигналов в своей общей библиотеке, она заменяет обработчики сигналов, установленные хост-приложением или другими общими библиотеками текущего процесса. Это может привести к неожиданному поведению.Известно, что Java в Linux использует сигнал SIGSEGV для своих внутренних функций и произойдет сбой, если сторонняя библиотека JNI переопределит обработчик сигнала SIGSEGV.
Маска FPU
Для совместимости с Delphi Free Pascal на i386 будет демаскировать все исключения FPU в модуле с плавающей запятой (но без установки обработчика для dll, см. выше). Это разоблачение выполняется до начала раздела инициализации. Если ваша DLL будет использоваться с хост-приложением, созданным с помощью другого компилятора (почти все другие компиляторы, кроме FPC и Delphi/ C++ Builder пожалуйста, проверьте C++ Builder), это будет сильно мешать исключению хост-приложения обработка.
После вызова LoadLibrary() ведущее приложение больше не сможет перехватывать какие-либо исключения с плавающей запятой. FPU внезапно получит возможность генерировать аппаратные исключения (в потоке, вызвавшем LoadLibrary()), и хост-приложение, скорее всего, не будет ожидать, что это произойдет, и не сможет правильно с этим справиться. Обходной путь заключается в том, чтобы поставить
в разделе инициализации, чтобы снова замаскировать их для потока, загрузившего библиотеку. Это не будет иметь каких-либо нежелательных побочных эффектов, кроме восстановления того, что хост-приложение имело все время. В вашей DLL вы все равно не смогли бы их поймать (по крайней мере, не в Windows, см. выше). Если вам действительно нужно отловить деление на ноль и связанные с ним ошибки в библиотеке DLL, написанной для приложения, отличного от FPC, вам нужно
- установить обработчик, как указано выше
- временно размаскировать FPU перед попыткой
- снова замаскируйте его, прежде чем вернуться в основное приложение
Завершение
Каждый блок может содержать раздел финализации. Порядок является обратным порядку секций инициализации.
После того, как все разделы завершения будут выполнены, будет вызвана процедура, которую вы ранее назначили для Dll_Process_Detach_Hook.
- все остальные блоки уже будут доработаны
- части RTL могут больше не работать должным образом
- создание и освобождение объектов в куче или даже использование строк Pascal внутри этой процедуры — верный способ вызвать проблемы.
Если вам нужно останавливать потоки и освобождать объекты, вы должны найти способ сделать это до выгрузки библиотеки — слишком поздно делать это здесь.
Версии, распространение
Библиотеки со временем растут и меняются. Добавление новых функций не проблема, но удаление общедоступного метода или изменение его параметров делает библиотеку несовместимой. Это означает, что либо установленная библиотека (.so, .dll, .dylib) заменяется на совместимую, либо в систему необходимо добавить новую библиотеку. Вот почему каждая библиотека содержит версию.
Что нужно сделать: объясните, как установить/использовать эту версию как в Windows, так и в *nix
Чтобы загрузить динамическую библиотеку (dlopen или модуль dynlibs), необходимо знать правильное имя файла. В Linux это означает, что вы должны знать номер версии.
Параметры функции определяются с использованием нотации Паскаля - имя: тип. Параметры разделяются запятыми, и каждый параметр должен быть явно указан:
Вы можете использовать запятую в конце при объявлении параметров функции:
Аргументы по умолчанию
Параметры функции могут иметь значения по умолчанию, которые используются при пропуске соответствующего аргумента. Это уменьшает количество перегрузок:
Значение по умолчанию определяется с помощью = после типа.
Если параметр по умолчанию предшествует параметру без значения по умолчанию, значение по умолчанию можно использовать только путем вызова функции с именованными аргументами:
Если последним аргументом после параметров по умолчанию является лямбда, вы можете передать его либо как именованный аргумент, либо вне круглых скобок:
fun foo( bar: Int = 0, baz: Int = 1, qux: () -> Unit, ) < /*. */ >foo(1) < println("hello") >// Использует значение по умолчанию baz = 1 foo(qux = < println("hello") >) // Использует оба значения по умолчанию bar = 0 и baz = 1 foo < println("hello") >// Используются оба значения по умолчанию: bar = 0 и baz = 1
Именованные аргументы
При вызове функции вы можете назвать один или несколько ее аргументов. Это может быть полезно, когда у функции много аргументов и трудно связать значение с аргументом, особенно если это логическое значение или значение NULL.
Когда вы используете именованные аргументы в вызове функции, вы можете свободно менять порядок их перечисления, а если вы хотите использовать их значения по умолчанию, вы можете вообще не использовать эти аргументы.
Рассмотрите следующую функцию, reformat() , которая имеет 4 аргумента со значениями по умолчанию.
забавное переформатирование (str: String, normalizeCase: Boolean = true, upperCaseFirstLetter: Boolean = true, DivisionByCamelHumps: Boolean = false, wordSeparator: Char = ' ', ) < /*. */ >
При вызове этой функции вам не нужно называть все ее аргументы:
Вы можете пропустить все значения со значениями по умолчанию:
Вы также можете пропустить определенные аргументы со значениями по умолчанию, а не все. Однако после первого пропущенного аргумента вы должны назвать все последующие аргументы:
Вы можете передать переменное количество аргументов ( vararg ) с именами, используя оператор расширения:
В JVM: вы не можете использовать синтаксис именованных аргументов при вызове функций Java, потому что байт-код Java не всегда сохраняет имена параметров функции.
Функции, возвращающие единицы измерения
Если функция не возвращает полезного значения, ее тип возвращаемого значения — Unit . Unit — это тип, имеющий только одно значение — Unit. Это значение не обязательно возвращать явно:
Объявление возвращаемого типа Unit также является необязательным. Приведенный выше код эквивалентен:
Функции с одним выражением
Когда функция возвращает одно выражение, фигурные скобки можно опустить, а тело указать после символа =:
Явное объявление возвращаемого типа является необязательным, если это может быть определено компилятором:
Явные возвращаемые типы
Функции с блочным телом всегда должны указывать возвращаемые типы явно, если только не предполагается, что они возвращают Unit , и в этом случае указывать возвращаемый тип необязательно.
Kotlin не выводит возвращаемые типы для функций с блочными телами, потому что такие функции могут иметь сложный поток управления в теле, а тип возвращаемого значения будет неочевидным для читателя (а иногда даже для компилятора).
Переменное количество аргументов (varargs)
Вы можете пометить параметр функции (обычно последний) модификатором vararg:
В этом случае вы можете передать функции переменное количество аргументов:
Внутри функции vararg -параметр типа T виден как массив T , как в приведенном выше примере, где переменная ts имеет тип Array .
Только один параметр может быть помечен как vararg . Если параметр vararg не является последним в списке, значения для последующих параметров могут быть переданы с использованием синтаксиса именованного аргумента или, если параметр имеет тип функции, путем передачи лямбда-выражения вне круглых скобок.
При вызове функции с переменным аргументом аргументы можно передавать по отдельности, например asList(1, 2, 3) . Если у вас уже есть массив и вы хотите передать его содержимое в функцию, используйте оператор spread (поставьте перед массивом * ):
Если вы хотите передать массив примитивного типа в vararg , вам нужно преобразовать его в обычный (типизированный) массив с помощью функции toTypedArray():
val a = intArrayOf(1, 2, 3) // IntArray — массив примитивных типов val list = asList(-1, 0, *a.toTypedArray(), 4)
Инфиксная нотация
Функции, помеченные ключевым словом инфикс, также могут вызываться с использованием инфиксной нотации (без точки и круглых скобок для вызова). Инфиксные функции должны соответствовать следующим требованиям:
Они должны быть функциями-членами или функциями расширения.
Они должны иметь один параметр.
инфикс fun Int.shl(x: Int): Int < . >// вызов функции с использованием инфиксной записи 1 shl 2 // аналогичен 1.shl(2)
Вызовы функций Infix имеют более низкий приоритет, чем арифметические операторы, приведения типов и оператор rangeTo. Следующие выражения эквивалентны:
1 шл 2 + 3 эквивалентен 1 шл (2 + 3)
0, пока n * 2 не будет эквивалентно 0, пока (n * 2)
xs union ys as Set эквивалентен xs union (ys as Set)
С другой стороны, приоритет вызова инфиксной функции выше, чем у логических операторов && и || , is - и in -checks, и некоторые другие операторы. Эти выражения также эквивалентны:
a && b xor c эквивалентно a && (b xor c)
a xor b в c эквивалентно (a xor b) в c
Обратите внимание, что инфиксные функции всегда требуют указания как получателя, так и параметра. Когда вы вызываете метод текущего получателя, используя инфиксную нотацию, используйте это явно. Это необходимо для обеспечения однозначного синтаксического анализа.
Область действия
Локальные функции
Kotlin поддерживает локальные функции, которые являются функциями внутри других функций:
Локальная функция может обращаться к локальным переменным внешних функций (замыкание). В приведенном выше случае посещенная может быть локальной переменной:
Функции участника
Функция-член — это функция, определенная внутри класса или объекта:
Функции-члены вызываются с помощью записи через точку:
Дополнительную информацию о классах и переопределяющих членах см. в разделе Классы и наследование.
Общие функции
Функции могут иметь общие параметры, которые указываются с помощью угловых скобок перед именем функции:
Дополнительную информацию о универсальных функциях см. в разделе Универсальные функции.
Хвостовые рекурсивные функции
Kotlin поддерживает стиль функционального программирования, известный как хвостовая рекурсия. Для некоторых алгоритмов, которые обычно используют циклы, вы можете вместо этого использовать рекурсивную функцию без риска переполнения стека.Когда функция помечена модификатором tailrec и соответствует требуемым формальным условиям, компилятор оптимизирует рекурсию, оставляя вместо нее быструю и эффективную версию на основе цикла:
val eps = 1E-10 // "достаточно хорошо", может быть 10^-15 tailrec fun findFixPoint(x: Double = 1.0): Double = if (Math.abs(x - Math.cos(x)) < eps) x иначе findFixPoint(Math.cos(x))
Этот код вычисляет фиксированную точку косинуса, который является математической константой. Он просто многократно вызывает Math.cos, начиная с 1.0, пока результат не перестанет меняться, что дает результат 0,7390851332151611 для указанной точности в eps. Полученный код эквивалентен этому более традиционному стилю:
Чтобы иметь право на использование модификатора tailrec, функция должна вызывать себя в качестве последней операции, которую она выполняет. Вы не можете использовать хвостовую рекурсию, когда есть больше кода после рекурсивного вызова, внутри блоков try/catch/finally или в открытых функциях. В настоящее время хвостовая рекурсия поддерживается Kotlin для JVM и Kotlin/Native.
Читайте также: