美文网首页Lisp
[Emacs Lisp] 启用变量的词法作用域

[Emacs Lisp] 启用变量的词法作用域

作者: 何幻 | 来源:发表于2017-05-10 14:11 被阅读114次

1. setq lexical-binding失效

从Emacs 24开始,Emacs可以启用变量的lexical binding模式,
Emacs Lisp Reference:11.9.4 Using Lexical Binding中提到,

When loading an Emacs Lisp file or evaluating a Lisp buffer, lexical binding is enabled if the buffer-local variable lexical-binding is non-nil:

—— Variable: lexical-binding
If this buffer-local variable is non-nil, Emacs Lisp files and buffers are evaluated using lexical binding instead of dynamic binding. (However, special variables are still dynamically bound; see below.) If nil, dynamic binding is used for all local variables. This variable is typically set for a whole Emacs Lisp file, as a file local variable.

Note that unlike other such variables, this one must be set in the first line of a file.

然而,以下代码,M-x eval-buffer之后,仍然会报错,
仍然使用了变量的dynamic binding模式,

(setq lexical-binding t)

(setq test (let ((foo "bar"))
         (lambda () 
           foo)))

(let ((foo "something-else"))
  (funcall test))    ; "something-else"

(funcall test)    ; Error! Symbol’s value as variable is void: foo

注:
(1)依次对每个表达式使用:M-x eval-last-sexp(快捷键:C-x C-e),
是不会报错的,确实启用了词法作用域。
但是使用M-x eval-buffer求值整个buffer,或者在其他文件中load本文件时,就会报错。
(2)M-x eval-buffer,可以简写为M-x ev-b

2. 解决方案

将文件的第一行改成:; -*- lexical-binding: t -*-
Emacs Version: 25.2

例如:M-x eval-bufferload都不报错,启用了词法作用域。

; -*- lexical-binding: t -*-

(setq test (let ((foo "bar"))
         (lambda () 
           foo)))

(let ((foo "something-else"))
  (funcall test))    ; "bar"

(funcall test)    ; "bar"

注:
(1); -*- lexical-binding: t -*-必须位于文件或者buffer的第一行。
(2)这条指令是以注释的方式存在的,在-*- ... -*-外面可以写任何其他注释,此外多个“;”肯定也是可以的“;;”,例如:;; 123 -*- lexical-binding: t -*- 456

3. File Variables

-*- mode: modename; var: value; ... -*-
类似这样的写法,实际上是在Emacs中指定了File Variables。

GNU Emacs manual: 51.2.4.1 Specifying File Variables中指出,

There are two ways to specify file local variable values: in the first line, or with a local variables list.

Here's how to specify them in the first line:

-*- mode: modename; var: value; ... -*-

A local variables list starts with a line containing the string ‘Local Variables:’, and ends with a line containing the string ‘End:’. In between come the variable names and values, one set per line, like this:

/* Local Variables:  */
/* mode: c           */
/* comment-column: 0 */
/* End:              */

参考

GNU Emacs manual
GNU Emacs Lisp Reference Manual
Emacs Wiki: Lexical binding

相关文章

  • [Emacs Lisp] 启用变量的词法作用域

    1. setq lexical-binding失效 从Emacs 24开始,Emacs可以启用变量的lexical...

  • Dynamic Scoping in Scheme

    词法作用域 vs 动态作用域 scheme是一门采用词法作用域(lexical scoping)的lisp方言,这...

  • js中的作用域

    作用域就是决定变量有效范围 作用域按决定的时期来区分可分为词法作用域和动态作用域词法作用域: 词法作用域就是作用域...

  • JS基础-作用域与闭包

    1.理解词法作用域和动态作用域 词法作用域:定义在词法阶段的作用域换言之,词法作用域是由你在写代码时将变量和块作用...

  • 你不知道的JavaScript:词法作用域

    词法作用域 简单的说,词法作用域就是定义在词法阶段的作用域。词法作用域就是由你写代码时将变量和块作用域写在哪里来决...

  • 前端笔试中常考题--js的函数与变量提升问题

    先谈谈作用域#### -- 什么是作用域?就是某个变量有(起)作用的范围;--词法作用域和动态作用域词法作用域:在...

  • 「JS」变量作用域

    作用域介绍静态作用域动态作用域 JavaScript 变量作用域词法环境组成创建结构关于词法环境的问题with 语...

  • 2、词法作用域

    词法作用域 简单地说,词法作用域就是定义在词法阶段的作用域。换句话说,词法作用域是由你在写代码时将变量和块作用域写...

  • YOU DON'T KNOW JS 笔记 2

    第二章 词法作用域 词法作用域是定义在词法阶段的作用域 由写代码时将变量和块作用域写在哪里决定 全局变量会自动成为...

  • 你不知道的JavaScript(二)|作用域和闭包

    词法阶段简单地说,词法作用域就是定义在词法阶段的作用域。换句话说,词法作用域是由你在写代码时将变量和块作用域写在哪...

网友评论

    本文标题:[Emacs Lisp] 启用变量的词法作用域

    本文链接:https://www.haomeiwen.com/subject/nwxgtxtx.html