Spec-Zone.ru › Elisp

Встроенные функции

Встроенная функция — это функция, которая работает так же, как обычная функция, за одним исключением: при компиляции вызова этой функции в байткод (см. Компиляция в байткод) определение функции подставляется в вызывающий код.

Простейший способ определить встроенную функцию — написать defsubst вместо defun. Остальная часть определения выглядит точно так же, но использование defsubst указывает, что функцию следует встроить при компиляции в байткод.

Макрос: defsubst name args [doc] [declare] [interactive] body…

Этот макрос определяет встроенную функцию. Его синтаксис в точности совпадает с синтаксисом defun (см. Определение функций).

Встраивание функции часто ускоряет выполнение её вызовов. Однако у этого есть и недостатки. Во-первых, это снижает гибкость: если изменить определение функции, уже встроенные вызовы продолжат использовать старое определение, пока их не скомпилируют заново.

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

Кроме того, встроенные функции плохо подходят для отладки, трассировки и добавления советов (см. Добавление советов к функциям Emacs Lisp). Поскольку простота отладки и гибкость переопределения функций — важные особенности Emacs, не следует встраивать функцию, даже если она небольшая, если только её скорость не имеет решающего значения и вы не проверили время выполнения кода, чтобы убедиться, что использование defun действительно приводит к проблемам с производительностью.

После определения встроенной функции её встраивание можно выполнить позднее в том же файле, как и для макросов.

Можно использовать defmacro, чтобы определить макрос, раскрывающийся в тот же код, который выполняла бы встроенная функция (см. Макросы). Однако такой макрос можно будет использовать только непосредственно в выражениях — вызвать макрос с помощью apply, mapcar и так далее нельзя. Кроме того, преобразование обычной функции в макрос требует некоторых усилий. Преобразовать её во встроенную функцию просто: достаточно заменить defun на defsubst. Поскольку каждый аргумент встроенной функции вычисляется ровно один раз, вам не нужно беспокоиться о том, сколько раз тело функции использует аргументы, как это приходится делать с макросами.

В качестве альтернативы можно определить функцию, предоставив код, который будет встраивать её как макрос компилятора (см. Форма declare). Это можно сделать с помощью следующих макросов.

Макрос: define-inline name args [doc] [declare] body…

Определяет функцию name, предоставляя код для её встраивания в виде макроса компилятора. Функция принимает список аргументов args и имеет указанное тело body.

Если указан doc, он должен быть строкой документации функции (см. Строки документации функций); если указан declare, он должен быть формой declare (см. Форма declare), задающей метаданные функции. Помимо обычных объявлений, declare может включать (noinline NOINLINE), когда не-nil NOINLINE запрещает Emacs встраивать определённую функцию.

Функции, определённые с помощью 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-2026 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Inline-Functions.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API