惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
DataBreaches.Net
L
LangChain Blog
博客园_首页
J
Java Code Geeks
博客园 - 【当耐特】
Microsoft Azure Blog
Microsoft Azure Blog
小众软件
小众软件
WordPress大学
WordPress大学
V
Visual Studio Blog
T
The Blog of Author Tim Ferriss
U
Unit 42
酷 壳 – CoolShell
酷 壳 – CoolShell
Recent Announcements
Recent Announcements
C
Check Point Blog
IT之家
IT之家
Engineering at Meta
Engineering at Meta
N
Netflix TechBlog - Medium
A
About on SuperTechFans
aimingoo的专栏
aimingoo的专栏
D
Docker
有赞技术团队
有赞技术团队
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
阮一峰的网络日志
阮一峰的网络日志
I
InfoQ

暗无天日

读:AI Agent 安全日志——从可见性与隐私的两难说起 - 暗无天日 AI写作的语言指纹——如何让文字不那么像机器 - 暗无天日 读:50 条 Claude Code 技巧——一个工程经理的六个月使用心得 读:AI 辅助开发为什么让 E2E 测试更有价值 - 暗无天日 读:在Emacs中使用Claude Code(Spacemacs适配版) - 暗无天日 Claude Code 背后的工程哲学——读 Agent Harness Engineering 读:Agent Harness Engineering——AI 智能体不只是模型,还有套件 - 暗无天日 browser-harness:让 AI 直接接管你的浏览器 - 暗无天日 读:Security-First CI/CD —— DevSecOps 自动化实践指南 TIL: 数字小键盘的小数点陷阱与行内算术求值 - 暗无天日 读:Immutability 不是万能药,它是一种权衡 - 暗无天日 Conducty:给 Claude Code 加上项目记忆和并行执行能力 - 暗无天日 读 — GitHub Trending 里的 Claude Code 技能包 读 — Prompt Caching 省钱指南 TIL: Emacs 中那些跟鼠标配合的冷门快捷键 - 暗无天日 读:Anvil——把 Emacs 变成 AI 的工具服务器 读:Emacs 代码折叠终极指南 - 暗无天日 读:Clojure 搭车客指南 - 暗无天日 git推送失败后恢复仓库损坏的完整记录 - 暗无天日 多智能体系统的两个有效模式——以及对 Claude Code 用户的启示 - 暗无天日 用 Org Babel 写 Literate 博文:扩展执行 + 定制导出 proced:Emacs 内置的进程查看器 - 暗无天日 从 proced 定制中学到的 Elisp 模式 读:让 Emacs proced 在 macOS 上显示 CPU 和内存 异步编程的函数着色税 - 暗无天日 链式调用的代价:JavaScript 和 Clojure 的共同教训 - 暗无天日 hyperfine:命令行基准测试工具 - 暗无天日 管道中的变量去哪了?——子 shell 作用域陷阱 - 暗无天日 开源包装器的信任陷阱:四个危险信号 - 暗无天日 程序员愿意为 AI 写文档,却不愿为同事写 - 暗无天日
读:The Many Faces of flet——Elisp 局部函数的三种写法
2026-05-19 · via 暗无天日

cl-flet 的行为和 let 一样,只不过它绑定的是函数而非变量。定义只在 cl-flet 的 body 内部可见:

(cl-flet ((double (n) (* n 2)))
  (double 21))
42

关键陷阱在这里: cl-flet 的绑定是词法作用域的,也就是说,被调用的其他函数看不到这个覆盖:

(defun my-helper () (+ 1 2))
(defun my-caller () (my-helper))

(cl-flet ((my-helper () 999))
  (my-caller))
3

my-caller 内部调用 my-helper 时,看到的仍然是全局定义的那个版本,返回 3 而不是 999。

为什么会这样?因为 cl-flet 用的是词法作用域:它定义的 my-helper 只在 cl-flet 的 body 源代码文本里可见。编译器在编译 my-caller 时, my-caller 的源代码里写的是 (my-helper) ,编译器在它所在的作用域里找到了全局的那个 my-helper ,于是把这个引用固定下来了。后面 cl-flet 再怎么定义局部的 my-helper ,都跟已经编译好的 my-caller 没关系了。

这和旧 flet 的行为完全相反。旧 flet 直接去改全局 function cell 里的内容,所有函数在运行时查找 my-helper 时都会找到那个被替换的版本,不管调用者是谁、在哪里定义的。

同理, cl-flet 定义的函数在自己的定义体内也看不到自己:

(cl-flet ((fact (n)
            (if (<= n 1)
                1
              (* n (fact (- n 1))))))   (fact 5))
Symbol's function definition is void: fact

cl-flet 还有一个变体 cl-flet* ,行为就像 let* 之于 let :后面的绑定可以引用前面的。

日常使用中, cl-flet 是最常用的那个。当你只需要一个简单的局部 helper、不需要递归时,用它就对了。