Встроенные функции
Встроенная функция — это функция, которая работает так же, как и обычная функция, за исключением одного момента: при байткодировании вызова функции (см. Байткодирование) определение функции расширяется в вызывающей программе.
Простой способ определить встроенную функцию — это написать defsubst вместо defun. Остальная часть определения выглядит точно так же, но использование defsubst указывает на то, что она должна быть встроенной при байткодировании.
- Макрос: defsubst name args [doc] [declare] [interactive] body…
Этот макрос определяет встроенную функцию. Его синтаксис точно такой же, как и у
defun(см. Определение функций).
Преобразование функции во встроенную часто ускоряет её вызовы. Но у этого есть и недостатки. Во-первых, это снижает гибкость; если вы измените определение функции, вызовы, уже встроенные в код, по-прежнему будут использовать старое определение до тех пор, пока вы их не перекомпилируете.
Другой недостаток заключается в том, что преобразование большой функции во встроенную может увеличить размер скомпилированного кода как в файлах, так и в памяти. Поскольку преимущество встроенных функций в скорости наиболее велико для небольших функций, обычно не следует преобразовывать большие функции во встроенные.
Кроме того, встроенные функции плохо работают с отладкой, трассировкой и консультированием (см. Консультирование функций). Поскольку простота отладки и гибкость переопределения функций являются важными особенностями Emacs, не следует преобразовывать функцию во встроенную, даже если она небольшая, если её скорость не является действительно критически важной, и вы не пробовали её время, чтобы убедиться, что использование defun не вызывает проблем с производительностью.
После определения встроенной функции её встроенное расширение может быть выполнено позже в том же файле, как и для макросов.
Можно использовать defmacro для определения макроса, который расширяется в тот же код, что и встроенная функция (см. Макросы). Но этот макрос будет ограничен непосредственным использованием в выражениях — макрос нельзя вызывать с apply, mapcar и так далее. Кроме того, потребуется работа для преобразования обычной функции в макрос. Преобразование в встроенную функцию легко; просто замените defun на defsubst. Поскольку каждый аргумент встроенной функции вычисляется ровно один раз, вам не нужно беспокоиться о том, сколько раз тело использует аргументы, как в случае с макросами.
В качестве альтернативы вы можете определить функцию, предоставив код, который будет встроен в неё как макрос компилятора. Следующие макросы делают это возможным.
- Макрос: define-inline name args [doc] [declare] body…
-
Определите функцию name, предоставив код, который выполнит её инлайнинг, как макрос компилятора. Функция будет принимать список аргументов args и будет иметь указанное body.
Если присутствует doc, это должна быть строка документации функции (см. Документация функций); declare, если присутствует, должен быть формой
declare(см. Форма declare), определяющей метаданные функции.
Функции, определенные с помощью define-inline, имеют несколько преимуществ по сравнению с макросами, определенными с помощью defsubst или defmacro:
- - Их можно передавать в
mapcar(см. Функции отображения). - - Они более эффективны.
- - Они могут использоваться как формы-позиции для хранения значений (см. Обобщенные переменные).
- - Они ведут себя более предсказуемо, чем
cl-defsubst(см. Списки аргументов в Расширения Common Lisp для GNU Emacs Lisp).
Как и defmacro, функция, встроенная с помощью define-inline, наследует правила области видимости, динамические или лексические, из места вызова. См. Область видимости переменных.
Следующие макросы должны использоваться в теле функции, определенной с помощью define-inline.
- Макрос: inline-quote expression
Вывести expression для
define-inline. Это аналогично обратной кавычке (см. Обратная кавычка), но цитирует код и принимает только,, а не,@.
- Макрос: inline-letevals (bindings…) body…
-
Это предоставляет удобный способ гарантировать, что аргументы встроенной функции вычисляются ровно один раз, а также создавать локальные переменные.
Это аналогично
let(см. Локальные переменные): устанавливает локальные переменные, как указано в bindings, и затем вычисляет body с этими связываниями в силе.Каждый элемент bindings должен быть либо символом, либо списком вида
(var expr); результатом является вычисление expr и привязка var к результату. Однако, когда элемент bindings — это просто символ var, результат вычисления var перепривязывается к var (что довольно отличается от того, как работаетlet).Хвост bindings может быть либо
nil, либо символом, который должен содержать список аргументов, в этом случае каждый аргумент вычисляется, а символ привязывается к результирующему списку.
- Макрос: inline-const-p expression
Возвращает не-
nil, если значение expression уже известно.
- Макрос: inline-const-val expression
Возвращает значение expression.
- Макрос: inline-error format &rest args
Вызвать ошибку, отформатировав args в соответствии с format.
Вот пример использования define-inline:
(define-inline myaccessor (obj)
(inline-letevals (obj)
(inline-quote (if (foo-p ,obj) (aref (cdr ,obj) 3) (aref ,obj 2)))))
Это эквивалентно
(defsubst myaccessor (obj) (if (foo-p obj) (aref (cdr obj) 3) (aref obj 2)))
Copyright © 1990-1996, 1998-2022 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Inline-Functions.html