[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5. Первые трудности

В этой главе, мы закрепим знания, полученные в предыдущих главах, изучив несколько более сложных функций. Функция copy-to-buffer иллюстрирует использование в одном определении двух выражений save-excursion, а функция insert-buffer показывает использование * в выражении interactive, использование or и важную разницу между именем и объектом, к которому имя относится.

5.1 Определение copy-to-buffer  С set-buffer, get-buffer-create.
5.2 Определение insert-buffer  Только-чтение, и функция or.
5.3 Полное определение beginning-of-buffer  Использование goto-char,
                                point-min, и push-mark.
5.4 Обзор  
5.5 Упражнения с &optional аргументом  


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.1 Определение copy-to-buffer

После изучения принципа работы append-to-buffer, легко понять и copy-to-buffer. Эта функция копирует текст в буфер, но вместо того чтобы добавить его во второй буфер, она заменяет предыдущий текст в том буфере. Код для функции copy-to-buffer почти такой же, как и код для append-to-buffer, отличаясь только использованием erase-buffer и второй формы save-excursion. (See section The Definition of append-to-buffer, для описания append-to-buffer.)

Тело copy-to-buffer выглядит следующим образом

 
...
(interactive "BCopy to buffer: \nr")
  (let ((oldbuf (current-buffer)))
    (save-excursion
      (set-buffer (get-buffer-create buffer))
      (erase-buffer)
      (save-excursion
        (insert-buffer-substring oldbuf start end)))))

Все это очень похоже на то, что мы видели в append-to-buffer, только после того, как мы переключились в новый буфер куда и собираемся копировать текст, исходные тексты этих двух функции расходятся --- в функции copy-to-buffer уничтожается первоначальное содержание буфера. (Обычно это называют замещением --- чтобы заместить текст, Emacs стирает предыдущий текст и затем вставляет новый). После того, как стерто прежнее содержание буфера, второй раз используется save-excursion и вставляется новый текст.

Почему же save-excursion используется дважды? Давайте внимательно посмотрим что же делает эта функция.

Схематично, тело copy-to-buffer выглядит следующим образом:

 
(let (связать-oldbuf-со-значением-current-buffer)
  (save-excursion         ; Первое использование save-excursion.
    изменить-буфер
      (erase-buffer)
      (save-excursion     ; Второе использование save-excursion.
        вставить-блок-текста-из-oldbuf-в-буфер)))

Первое использование save-excursion вернет Emacs в буфер из которого мы копируем текст. Это ясно, и точно такой же код использовался в append-to-buffer. Зачем же использовать эту функцию второй раз? Причина этого заключается в том, что insert-buffer-substring всегда оставляет точку в конце вставленного региона текста. Второе использование save-excursion заставляет Emacs оставить точку в начале вставленного текста. В большинстве случаев, пользователи предпочитают обнаружить точку в начале вставленного текста. (Конечно, функция copy-to-buffer вернет пользователя в первоначальный буфер когда завершит свою работу --- но если пользователь потом переключится в тот буфер, то точка будет в начале текста. То есть второе использование save-excursion применяется для удобства).


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2 Определение insert-buffer

insert-buffer --- еще одна функция связанная с буферами. Эта команда копирует другой буфер в текущий буфер. Это обратное действие, если сравнивать с append-to-buffer и copy-to-buffer, поскольку они копируют регион текста из текущего буфера в другой буфер.

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

 
(defun insert-buffer (buffer)
  "Вставить после точки содержимое BUFFER.
Поставить метку после вставленного текста.
BUFFER может быть буфером или именем буфера."
  (interactive "*bInsert buffer: ")
  (or (bufferp buffer)
      (setq buffer (get-buffer buffer)))
  (let (start end newmark)
    (save-excursion
      (save-excursion
        (set-buffer buffer)
        (setq start (point-min) end (point-max)))
      (insert-buffer-substring buffer start end)
      (setq newmark (point)))
    (push-mark newmark)))

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

 
(defun insert-buffer (buffer)
  "документация..."
  (interactive "*bInsert buffer: ")
  тело...)

5.2.1 Интерактивное выражение в insert-buffer  Когда буфер только-для-чтения.
5.2.2 Тело функции insert-buffer  
5.2.3 insert-buffer с if вместо or  Используем if вместо or.
5.2.4 or в теле функции  
5.2.5 Выражение let в insert-buffer  Два выражения save-excursion.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2.1 Интерактивное выражение в insert-buffer

В insert-buffer, аргумент к объявлению interactive состоит из двух частей, звездочки `*', и строки `bInsert buffer: '.

Буфер только-для-чтения  
`b' в интерактивном выражении  


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

Буфер только-для-чтения

Звездочка используется в тех ситуациях, когда буфер открыт в режиме только-для-чтения --- то есть, это буфер, который нельзя изменять. Если insert-buffer вызвали из буфера только для чтения, то в эхо-области появится сообщение об ошибке и терминал издаст звуковой сигнал или мигнет --- вам не разрешено изменять текущий буфер. За звездочкой не должен следовать символ новой строки, отделяющий ее от аргумента.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

`b' в интерактивном выражении

Следующий аргумент в интерактивном объявлении начинается с буквы `b' в нижнем регистре. (Здесь есть отличие от текста функции append-to-buffer, в котором используется `B' в верхнем регистре. See section The Definition of append-to-buffer.) Строчная буква `b' сообщает интерпретатору Лиспа, что аргументом для этой функции должен быть существующий буфер или его имя. (Прописная буква `B' разрешает отсутствие буфера). Emacs запросит у вас имя буфера, предложив вам буфер по умолчанию, с возможностью дополнения. Если буфер не существует, то вы получите сообщение, которое гласит "No match" (Нет соответствия); и ваш терминал может издать звуковой сигнал.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2.2 Тело функции insert-buffer

Тело insert-buffer содержит две основные части --- выражение or и выражение let. Задача выражения or убедится в том, что аргумент buffer связан с существующим буфером, а не является только именем буфера. Тело выражения let содержит код, который копирует другой буфер в текущий буфер.

Схематично, что эти два выражения входят в состав функции insert-buffer следующим образом:

 
(defun insert-buffer (buffer)
  "документация..."
  (interactive "*bInsert buffer: ")
  (or ...
      ...
  (let (список-переменных)
      тело-let... )

Чтобы понять как выражение or проверяет что аргумент buffer связан с буфером, а не просто является именем буфера, нам вначале необходимо изучить функцию or.

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


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2.3 insert-buffer с if вместо or

Необходимо убедиться, что значение buffer --- это существующий буфер а не просто имя буфера. Если это просто имя, то тогда надо получить связанный с ним буфер.

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

На Лиспе, вы можете описать эту ситуацию следующим образом:

 
(if (not (не-нашел-гостя))
    (найти-и-взять-его-за-руку))

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

Используя предикат bufferp, который проверяет является ли буфером ли его аргумент или он является только его именем, мы можем записать следующее:

 
(if (not (bufferp buffer))              ; if-часть
    (setq buffer (get-buffer buffer)))  ; then-часть

Здесь, проверка-истина-ложь в выражении if --- это (not (bufferp buffer)); а then-часть --- выражение (setq buffer (get-buffer buffer)).

В проверке, функция bufferp возвращает истину если его аргумент --- буфер, и ложь, если его аргумент --- это имя буфера. (Последний символ в имени функции bufferp --- это символ `p'; как мы видели ранее, такое использование `p' подчеркивает, что эта функция является предикатом, что означает, что она проверяет, обладает ли ее аргумент каким-либо свойством. See section Using the Wrong Type Object as an Argument.)

Перед выражением (bufferp buffer, расположена функция not, так что проверка-истина-ложь выглядит следующим образом:

 
(not (bufferp buffer))

Функция not возвращает истину, если ее аргумент имеет значение ложь, и ложь, если ее аргумент истина. Так, что если (bufferp buffer) возвращает истину, то выражение not вернет ложь и наоборот --- то, что "не истина" это ложь, а то, что "не ложь" это истина.

С помощью этого теста выражение if, работает следующим образом --- если значение переменной buffer на самом деле буфер, а не только его имя, то тогда проверка-истина-ложь возвращает ложь и then-часть выражения if не вычисляется. Это правильно, поскольку нам и не надо ничего делать, если переменная buffer на самом деле связана с буфером.

С другой стороны, когда значение buffer --- это не сам буфер, а только его имя, то проверка-истина-ложь возвращает истину, и тогда вычисляется then-часть всего выражения if. В этом случае then-часть --- это (setq buffer (get-buffer buffer)). Это выражения с помощью функции get-buffer возвращает фактический буфер, который задан именем. Затем setq связывает переменную buffer со значением самого буфера, замещая таким образом предыдущее значение (которое было именем буфера).


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2.4 or в теле функции

Цель выражения or в insert-buffer, убедиться, что аргумент buffer связан с буфером, а не с именем оного. В предыдущем разделе мы рассмотрели, как это задачу можно выполнить с помощью выражения if. Однако в insert-buffer, на самом деле используется or. Для этого нам необходимо познакомиться с этой функцией.

У функции or может быть любое количество аргументов. Она вычисляет каждый аргумент по очереди и возвращает значение первого из них который вернул не nil. Также и это главная характеристика функции or, после этого она не вычисляет другие аргументы, если какой-то вернул значение не-nil.

Выражение or в функции insert-buffer выглядит следующим образом:

 
(or (bufferp buffer)
    (setq buffer (get-buffer buffer)))

Первый аргумент в or это выражение (bufferp buffer). Это выражение возвращает истину (то есть не-nil) если переменная buffer на самом деле связана с буфером, а не с именем буфера. В общем выражении or в таком случае все выражение or возвращает истину и не вычисляет свое следующее выражение---так и надо, ведь нам уже не надо ничего делать если значение buffer сам буфер.

С другой стороны, если значения (bufferp buffer) это nil, то есть если значением переменной buffer было имя буфера, то интерпретатор Лиспа вычислит следующий элемент в выражении or. Это выражение (setq buffer (get-buffer buffer)). Это выражение вернет значение не-nil, а значение к которому сейчас связана переменная buffer, то есть сам буфер, а не его имя.

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

Кстати, с помощью or, ситуацию со швейцаром можно записать следующим образом:

 
(or (не-нашел-гостя) (найти-и-взять-его-за-руку))


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2.5 Выражение let в insert-buffer

После того, как мы убедились, что переменная buffer связана с буфером, а не с его именем, в insert-buffer вычисляется выражение let. В нем задаются три локальные переменные: start, end и newmark и им присваивается первоначальное значение nil. Эти переменные используются в теле выражения let и временно маскируют переменные с такими же именами, но определенные вне этой функции.

Тело let содержит два выражения save-excursion. Вначале, мы рассмотрим в деталях внутренней выражение save-excursion. Оно выглядит следующим образом:

 
(save-excursion
  (set-buffer buffer)
  (setq start (point-min) end (point-max)))

Выражение (set-buffer buffer) переключает внимание Emacs от текущего буфера к тому из которого будет копироваться текст. В этом буфере, переменные start и end связываются с началом и концом этого буфера с помощью команд point-min и point-max. Отметим использование функции setq, которая назначает значение сразу двум переменным. Первому аргументу setq присваивается значение второго аргумента, а третьему аргументу --- значение четвертого.

После вычисление тела внутреннего выражения save-excursion, Emacs восстанавливает первоначальный буфер, но при этом значения start и end остаются теми же, то есть они содержат точки начала и конца буфера.

Внешнее выражение save-excursion выглядит следующим образом:

 
(save-excursion
  (внутреннее-expression-save-excursion
     (идем-в-новый-буфер-и-устанавливаем-start-и-end)
  (insert-buffer-substring buffer start end)
  (setq newmark (point)))

Функция insert-buffer-substring копирует текст в текущий буфер из области ограниченной точками start и end буфера buffer. Поскольку между точками start и end находиться весь второй буфер, то он и будет скопирован в ваш текущий буфер. Затем значение точки, которая будет в конце вставленного текста записывается в переменную newmark.

После вычисления тела внутреннего save-excursion, точка и метка восстанавливаются к их первоначальным значениям.

Однако это довольно удобно расположить метку в конце вставленного недавно текста, а точку в начале. В переменной newmark записан конец вставленного текста. В последней строке выражения let, с помощью выражения (push-mark newmark) метка устанавливается на это место. (Предыдущая метка все еще доступна --- она занесена в кольцо меток и вы можете вернуться к ней с помощью сочетания клавиш C-u C-SPC). В тоже время, точка расположена в начале вставленного текста, располагаясь там же, где она была до вызова функции insert-buffer.

Все выражение let выглядит следующим образом:

 
(let (start end newmark)
  (save-excursion
    (save-excursion
      (set-buffer buffer)
      (setq start (point-min) end (point-max)))
    (insert-buffer-substring buffer start end)
    (setq newmark (point)))
  (push-mark newmark))

Как и в функции append-to-buffer, в функции insert-buffer, используются let, save-excursion, и set-buffer. Кроме этого, в этой функции проиллюстрирован еще один способ использования функции or. Все эти функции являются строительными блоками, которые мы будем использовать снова и снова.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.3 Полное определение beginning-of-buffer

Мы уже рассмотрели основную идею функции beginning-of-buffer. (See section A Simplified beginning-of-buffer Definition.) Сейчас давайте опишем ее полностью.

Мы уже упоминали, что когда функция beginning-of-buffer запускается с одним аргументом, то она перемещает курсор в начало буфера, оставляя метку на предыдущем положении курсора. Однако, если эту команду запустить с числовым аргументом от одного до десяти, то тогда эта функция будет рассматривать это число, как долю к общей длине буфера, измеренной в десятых долях, и переместит курсор в ту часть буфера, которая соответствует заданному значению. То есть вы можете или вызвать функцию с помощью M-<, что переместит курсор к началу буфера, или с помощью C-u 7 M-<, что переместит курсор к точке находящейся в 70% процентов от начала буфера. Если число больше чем десять, тогда курсор будет перемещен в конец буфера.

Функцию beginning-of-buffer можно вызывать с аргументом или без него. То есть аргумент является необязательным.

5.3.1 Необязательные аргументы  
5.3.2 beginning-of-buffer с аргументом  Пример с необязательным аргументом.
5.3.3 Полный текст beginning-of-buffer  


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.3.1 Необязательные аргументы

Если не сказать заранее, то интерпретатор будет ожидать, что функцию в определении которой был задан аргумент, будут вызывать с аргументом. Если ее вызвать без аргументов, тогда вы получите сообщение об ошибке которое гласит `Wrong number of arguments'.

Однако в Лиспе существует возможность задать необязательные аргументы --- для этого используется ключевое слово &optional. (`&' перед `optional' --- это часть ключевого слова). В определении функции, если за словом &optional, следует аргумент, то тогда при вызове функции ей необязательно передавать какие-либо аргументы.

Следовательно первая строка в определении функции beginnig-of-buffer, выглядит следующим образом:

 
(defun beginning-of-buffer (&optional arg)

Схематично, вся функция выглядит следующим образом:

 
(defun beginning-of-buffer (&optional arg)
  "документация..."
  (interactive "P")
  (push-mark)
  (goto-char 
    (если-есть-аргумент
        рассчитать-куда-переместить-курсор
      иначе-переместить-курсор-в
      (point-min))))

Эта функция похожа на simplified-beginning-of-buffer, за исключением того, что выражение interactive идет с аргументом "P" и за выражением if-then-else, где вычисляется куда переместить курсор, если задан аргумент, идет функция goto-char.

"P" в выражении interactive заставляет Emacs передать в функцию префикс-аргумент, если он был задан. Префикс-аргумент можно задать или с помощью клавиши META, за которой будет следовать число, или нажав C-u, и затем набрав какое-нибудь число (если вы не задали число, то по умолчанию, C-u назначает ему 4).

Проверка-истина-ложь в выражение if очень проста --- это просто аргумент arg. Если с arg связано значение не-nil, то есть функцию beginning-of-buffer вызвали с аргументом, то тогда проверка-истина-ложь возвращает истину и вычисляется then-часть выражения if. С другой стороны, если функцию beginning-of-buffer вызвали без аргумента, то тогда значением arg будет nil, и будет вычислена else-часть выражения if. Else-часть это просто point-min, в этом случае полностью выражение для goto-char будет выглядеть следующим образом (goto-char (point-min)), что мы и видели в упрощенной версии beginning-of-buffer.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.3.2 beginning-of-buffer с аргументом

Если beginning-of-buffer вызван с аргументом, то тогда вычисляется выражение, в котором рассчитывается значение, которое будет передано функции goto-char. На первый взгляд это выражение кажется довольно сложным. Там много арифметики и есть вложенное if. Выглядит оно следующим образом:

 
(if (> (buffer-size) 10000)
    ;; Чтобы избежать переполнения в буферах больших размеров!
    (* (prefix-numeric-value arg) (/ (buffer-size) 10))
  (/
   (+ 10
      (*
       (buffer-size) (prefix-numeric-value arg))) 10))

Как и другие сложные выражение, это выражение можно понять, если представить логику работы в виде шаблона; в нашем случае шаблона для выражения if-then-else. В схематичной форме, выражение выглядит следующим образом:

 
(if (буфер-большой
    разделить-размер-буфера-на-10-и-умножить-на-arg
  иначе-посчитать-по-другому

Проверка-истина-ложь в выражении if, проверяет размер буфера. Это вызвано тем, что в 18 версии Emacs Лисп в вычислениях используются числа не больше, чем восемь миллионов или около того (больше вроде и не надо), и может получиться большее число, если буфер очень большой. Для этого существует термин `переполнение', если число больше, чем самое большое.

То есть перед нами два случая: если буфер большой и если не очень.

Что происходит в больших буферах  
Что происходит в маленьких буферах  


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

Что происходит в больших буферах

В функции beginning-of-buffer, внутреннее выражение if, проверяет больше ли размер буфера, чем 10,000 символов. Для этого используются функции > и buffer-size. Эта строка выглядит следующим образом:

 
(if (> (buffer-size) 10000)

Если буфер больше, то тогда выполняется then-часть всего выражения if. Она выглядит следующим образом (после надлежащего форматирования):

 
(* 
  (prefix-numeric-value arg) 
  (/ (buffer-size) 10))

Это просто операция умножения с двумя аргументами.

Первый аргумент --- это (prefix-numeric-value arg). Когда interactive задан аргумент "P", то в функцию передается так называемый "сырой префикс-аргумент", а не число. (Это число в списке). Для функции * требуется числовое значение и prefih-numeric-value переводит "сырой префикс-аргумент" в число.

Второй аргумент --- это (/ (buffer-size) 10). Это выражение делит численное значение длины буфер на десять. В результате мы получаем число, которое говорит нам сколько символов содержится в одной десятой нашего буфера. (В Лиспе, / используют для деления, а * для умножения).

Схематично все выражение для умножения можно представить следующим образом:

 
(* численное-значение-префикс-аргумента
   число-символов-в-одной-десятой-буфера)

Например, если префикс-аргумент равен `7', то после умножения числа символов в одной десятой на 7 мы получим число которому соответствует точка на расстоянии в 70% от начала буфера.

Таким образом, если буфер большой, то все выражение для goto-char будет выглядеть следующим образом:

 
(goto-char (* (prefix-numeric-value arg)
              (/ (buffer-size) 10)))

Это переместит курсор куда мы хотим.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

Что происходит в маленьких буферах

Если буфер содержит меньше чем 10,000 символов, то вычисление будет немножко другим. Вам может показаться, что это излишнее усложнение, поскольку и первый способ вполне себе хорош. Однако в небольших буферах первый способ не совсем точно перемещает курсор --- второй метод делает лучше.

Код выглядит следующим образом:

 
(/ (+ 10 (* (buffer-size) (prefix-numeric-value arg))) 10))

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

 
  (/
   (+ 10
      (*
       (buffer-size)
       (prefix-numeric-value arg)))
   10))

Сейчас хорошо видно, что самое внутреннее выражение это (prefix-numeric-value arg), где необработанный префикс-аргумент переводиться в численную форму. В следующем выражении полученое число умножается на размер буфера:

 
(* (buffer-size) (prefix-numeric-value arg)

В результате получится число, которое может быть меньше чем размер буфера --- в семь раз если аргумент был 7. Затем к результату будет добавлено десять и в конце это большое число поделят на десять --- так мы и получим значение которое на один символ больше чем процентная позиция в буфере.

Конечное число будет передано в функцию goto-char и в результате курсор будет перемещен в нужное место.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.3.3 Полный текст beginning-of-buffer

А вот и полный текст функции beginning-of-buffer:

 
(defun beginning-of-buffer (&optional arg)
  "Переместить точку в начало буфера;
оставив метку в предыдущей позиции курсора.
С арг N, переместить точку в N/10 от начала
буфера.
Не используете эту функцию в своих программах!
\(goto-char (point-min)) быстрее и не устанавливает
метку."
  (interactive "P")
  (push-mark)
  (goto-char 
   (if arg
       (if (> (buffer-size) 10000)
           ;; Avoid overflow for large buffer sizes!
           (* (prefix-numeric-value arg)
              (/ (buffer-size) 10))
         (/ (+ 10 (* (buffer-size) 
                     (prefix-numeric-value arg))) 
            10))
     (point-min)))
  (if arg (forward-line 1)))

Кроме двух нюансов мы уже все обсудили. Во первых надо обсудить строку документации, и во вторых надо рассмотреть последнюю строку функции.

В строке документации, есть ссылка на выражение:

 
\(goto-char (point-min))  

Перед открывающей скобкой этого выражения стоит `\'. Это сообщает интерпретатору Лиспа, что выражение так и должно присутствовать в документации, и вычислять его не надо.

В последней строке функции beginning-of-buffer производиться перемещение курсора в начало строки, если команда была запущена с аргументом:

 
(if arg (forward-line 1)))

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


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.4 Обзор

Кратко повторим темы, которые мы изучили в этой главе.

or
Последовательно вычисляет свои аргументы, и возвращает значение первого из них, равного не-nil; если же все вернули nil, то результат всего выражения также будет nil. Короче говоря, эта функция возвращает первое истинное значение своих аргументов; она возвращает истину если один, или любой другой аргумент истинен.

and
Последовательно вычисляет свои аргументы, и если какой-либо из них вернет nil, то возвращает nil; если нет, то возвращает значение своего последнего аргумента. Короче говоря, возвращает истину, только если все аргументы истинны.

&optional
Это ключевое слово обозначает, что аргумент функции необязателен --- это значит, что функцию можно вызывать или с аргументом или без него.

prefix-numeric-value
Преобразует 'сырой префикс-аргумент' который возвращает (interactive "P") в численное значение.

forward-line
Перемещает курсор в начало следующей строки, или если задан аргумент, то на заданное число строк. Если буфер заканчивается раньше, то перемещает курсор в конец буфера, и возвращает количество строк на которые функция forward-line не смогла продвинуться.

erase-buffer
Удаляет все содержимое текущего буфера.

bufferp
Возвращает t если аргумент является буфером; в противном случае возвращает nil.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.5 Упражнения с &optional аргументом

Напишите интерактивную функцию с необязательным аргументом, которая проверяет является ли ее аргумент числом, меньше оно или больше оно чем значение переменно fill-column, и сообщает результат в виде сообщения в мини-буфере. Однако, если аргумент не передан, то в качестве значения по умолчанию должно использоваться число 56.


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated on March, 10 2004 using texi2html