相互依赖的 .el 文件的设计模式

Design pattern on mutually dependent .el files

随着包大小的增加,代码的可读性下降。最佳做法是根据功能将包分成不同的文件。有时,文件需要彼此的变量和函数。

示例:

foo.el

(defvar foo-data-path "~/foo/data/")
(foo-log-write 'somedata)

foo-log.el

(defvar foo-logfile (concat foo-data-path "foo.log"))
(defun foo-log-write (data)
  ;; Write to log file
  )

因为foo.el使用了foo-log-write的函数,所以我把(require 'foo-log)放在了foo.el中。

foo-log.el中,它使用foo.el中的foo-data-path,我是否也应该在其中放入(require 'foo)? 如果我不添加 (require 'foo).

,语法检查器总是抱怨 reference to free variable

我见过两种技术可以处理您描述的情况。应该注意的是,如果您不小心,可能会陷入循环依赖问题。虽然你可以在一个文件中多次要求,但如果它们相互依赖并且你的'provide行在最后,你很容易陷入循环。

我成功使用的两个解决方案是

  1. (首选)。将相互依赖的代码提取到第三个文件中,并让其他两个需要该文件。

  2. 当所有其他方法都失败并且您无法将事情排除在外并且无法避免相互依赖时,请确保至少有一个文件在开头具有 provide 语句。这通常不是一个好主意,因为如果您的文件在完成加载之前出错,您似乎已经满足了要求,但并非您期望加载的所有内容都会满足。

第二种技术有助于打破无限循环,因为您已经满足了其中一项提供要求。在文件末尾(通常应该在此处)提供 provide 的问题在于,在文件完全加载之前您无法满足 require 请求。但是,如果该文件需要另一个文件,它将首先加载该文件,然后再继续加载第一个文件。如果第二个文件也有一个 require 并且那个 require 是针对第一个文件的,emacs 将再次开始加载第一个文件,直到它满足第二个文件的 require 并绕过我们进行的循环。

通过将 provide 放在文件的开头,下次它遇到该文件的要求时,它不会尝试加载它,因为它会认为它已经加载了。循环被打破了。