Learning
VOL. XIII · NO. 01 · Elixir · 25 JUL 2026

Anki

Elixir 编程 · 25 JUL 2026 · 9 min read · 1,780 words
· · ·

Anki 背诵卡片 — Elixir 速通

格式说明:每张卡片包含 问题(正面) / 答案(背面) / 标签。 适合在 0001-0005 课程读完一遍后,挑这些纯记忆型概念制成卡片。


一、基础语法 / 数据结构

字面量类型

Q: Elixir 中 atom 是什么?给 3 个例子。 A: 像 Clojure 的 keyword / Haskell 的 Symbol。:ok:error:running:foo_bar。 BEAM 内部用地址比较,极快。是所有”标签 / 枚举”的基础。 Tags: elixir-basics

Q: Elixir 的 String 用什么引号?Charlist 用什么引号? A: String = 双引号 "hello"(UTF-8 binary)。 Charlist = 单引号 'hello'(Erlang 遗留的整数列表,几乎不用)。 Tags: elixir-basics

Q: Elixir 中 nilfalse 是什么关系? A: 都是 atom。nil = :nilfalse = :false||nilfalse 都视为”假”。unless x 等同于 if !x。 Tags: elixir-basics

Q: Keyword List [a: 1, b: 2] 等价于什么? A: [{:a, 1}, {:b, 2}] — 就是 list of tuples。 用于”命名参数 opts”,Keyword.get(opts, :key, default) 取值。 Tags: elixir-basics

Q: Tuple {:ok, value} 跟 Map %{a: 1} 的性能差异? A: Tuple 定长 N≤10,读写 O(1),比 Map 还快。用 case 模式匹配。 Map 是 hashmap,O(log n),按 key 随机访问。 Tags: elixir-basics

绑定 / 不可变

Q: x = 10; x = 20 在 Elixir 中是什么意思? A: 重新绑定到新值 20,不是修改。 Elixir 一切数据不可变,变量是”标签”不是”盒子”。 Tags: elixir-basics

Q: Pin operator ^x 的作用? A: 在模式匹配中防止重新绑定,沿用外面的 x 值。 case y do; ^x -> ...; _ -> ... end^x 表示”匹配 x 绑定的那个值”。 Tags: elixir-basics

Q: Elixir 中 = 跟 C/Java = 的根本区别? A: Elixir = 是模式匹配 + 绑定。 C/Java = 是赋值(修改内存)。 x = {1, 2} 在 Elixir 是”匹配 {1,2} 模式,绑定 x”;C 是”把 1,2 写入 x 内存”。 Tags: elixir-basics


二、模式匹配 / 控制流

Q: case expr do ... end_ 通配符放错位置会怎样? A: 永远匹配不上后面任何子句。 _ 必须放最后,定义顺序敏感——前定义先匹配。 Tags: elixir-pattern

Q: condcase 什么时候用? A: case — 模式匹配(按结构分支) cond — 布尔条件分支(像 if/elif 链) if/unless — 单分支 with — 链式 {:ok, x} 解包 Tags: elixir-control

Q: Elixir 的 if 跟 Java 的 if 区别? A: Elixir if 是表达式有返回值,可以放在 = 右边。 Java if 是语句,Java 14+ if 表达式才类似。 Tags: elixir-control

Q: Elixir 的”let it crash” 哲学实践是? A: 进程不防御性 try-catch 全部错误。崩了让 Supervisor 重启。 跟 Java “满屏 try-catch” 相反。 Tags: elixir-philosophy


三、并发 / OTP

Q: BEAM 进程的初始内存大小?跟 Java Thread、goroutine 对比? A: BEAM 进程 ~ 0.5 KB;goroutine ~ 2 KB;Java Thread ~ 512 KB。 单机可创建百万级 BEAM 进程。 Tags: elixir-concurrency

Q: BEAM 调度是抢占式还是协作式? A: 抢占式——每 2000 reductions 强制切换。 死循环不会卡死整个 VM(Go 的 goroutine 是协作式)。 Tags: elixir-concurrency

Q: GenServer.call vs GenServer.cast 区别? A: call 同步等 reply(阻塞);cast 异步不阻塞,立即返回。 call 失败有 timeout;cast 不返回任何错误(fire-and-forget)。 Tags: elixir-concurrency

Q: Supervisor 4 种重启策略? A: :one_for_one 一个崩了只重启那个(默认) :one_for_all 一个崩了全部重启 :rest_for_one 一个崩了它和它之后启动的子进程重启 :temporary 不重启 Tags: elixir-otp

Q: BEAM 进程之间通信方式? A: 唯一方式:消息传递(send(pid, msg))。不允许共享内存。 消息是值复制(小对象)或 COW(large binary)。 Tags: elixir-concurrency

Q: send(dead_pid, msg) 到不存在的 pid 会怎样? A: 消息丢失,无声无息。BEAM 不报错。 项目里 Oban 用 PG 持久化消息,进程挂了消息不丢。 Tags: elixir-concurrency


四、模块 / 宏 / 行为 / 协议

Q: def vs defp 区别? A: def 公开函数(外部可调);defp 私有函数(只能本模块内调)。 跟 Java public / private 类似。 Tags: elixir-module

Q: use vs import vs require vs alias 区别? A: alias — 给模块起别名(alias Pipeline.Repo 之后写 Repoimport — 导入函数到当前命名空间 require — 让宏可见(宏要先 require 才能用) use — 调对方模块的 __using__/1 宏,注入代码到当前模块 Tags: elixir-module

Q: use Oban.Worker 内部大致调什么? A: 调 Oban.Worker.__using__/1 宏,注入 use GenServer + @behaviour Oban.Worker + perform/1 框架代码。 Tags: elixir-macro

Q: Elixir 协议(Protocol)跟 Java interface 的核心区别? A: 协议可以给已有类型(包括第三方)加 dispatch。 Interface 不能给已存在的 class 加方法(除非改源码)。 Elixir 协议在编译期展开成 case 模式匹配,运行时极快。 Tags: elixir-protocol

Q: 行为(@behaviour)写在一个模块里,编译时会做什么? A: 读对方模块所有 @callback,检查当前模块是否实现全部。 漏实现:编译警告;签名错:编译错误。 Tags: elixir-behaviour

Q: defmacrodef 关键区别? A: defmacro编译期执行,接收和返回 AST;def运行期执行普通逻辑。 Elixir 宏跟 Clojure 宏同源于 homoiconicity(代码即数据)。 Tags: elixir-macro

Q: quote do 1 + 2 end 返回什么? A: AST 三元组 {:+, _, [1, 2]}。这是宏操作代码的基础。 Tags: elixir-macro

Q: Elixir 什么时候用协议 vs 行为? A: 协议 — 已有 N 个类型,想加统一接口(如”如何序列化”)。 行为 — 接口固定,实现可能多个(如依赖注入,运行时切换)。 Tags: elixir-polymorphism


五、Ecto / Oban

Q: Ecto Changeset 是什么? A: 一个流程描述(不是值):cast(白名单字段)+ validate_required(必填校验)。 Repo.insert!/1 提交 changeset。 Tags: elixir-ecto

Q: Repo.insert!Repo.insert 区别? A: ! 结尾的版本失败时抛异常;不带 ! 返回 {:ok, record}{:error, changeset}。 跟 Ruby 的 ! 区别(Ruby ! 表示 in-place 修改)。 Tags: elixir-ecto

Q: on_conflict: :nothing 的作用? A: PostgreSQL INSERT ... ON CONFLICT DO NOTHING——冲突时忽略。 用于幂等去重(拉消息时按主键)。 Tags: elixir-ecto

Q: Oban Worker 的 perform/1 接收什么? A: %Oban.Job{} struct(带 args 字段)。 内部就是个 GenServer,Oban 调度时调用 perform/1。 Tags: elixir-oban


六、错误处理

Q: Elixir 错误的两种表示? A: 1) {:ok, value} / {:error, reason} tagged tuple(预期错误,80% 场景) 2) try/rescue 异常(意外崩溃,20% 场景) 哲学:“errors are values, not exceptions”。 Tags: elixir-error

Q: Elixir 默认参数怎么写? A: def f(x \\ 0) —— \\ 双反斜杠。 跟 Python def f(x=0)= 不同。 Tags: elixir-syntax


七、与其他语言速记

Q: Elixir 跟 Go 的核心区别? A: Elixir 进程独立堆,消息传递唯一;Go goroutine 共享堆,channel 通信。 Elixir 抢占式调度;Go 协作式调度。 Elixir 支持热代码升级;Go 不支持。 Tags: elixir-vs-go

Q: Elixir 跟 Clojure 最像的? A: 都支持宏(homoiconic)、都是 FP、都是动态类型。 区别:Elixir 在 BEAM,Clojure 在 JVM。 Clojure 宏完全卫生,Elixir 宏手动卫生(var!)。 Tags: elixir-vs-clojure

Q: BEAM 进程 vs Java Thread vs goroutine 初始内存? A: BEAM 0.5 KB < goroutine 2 KB <<< Java Thread 512 KB。 1000x 差距。BEAM 单机百万进程。 Tags: elixir-runtime

Q: 99.999% 可用性 / 长连接选哪个语言? A: Elixir / Erlang(30 年电信验证)。 WhatsApp / Discord / Ericsson AXD301 都跑在 BEAM。 Tags: elixir-selection


八、ex/elixir 项目特有

Q: ex/elixir 项目里 Pipeline.Application.start/2 的监督树根是什么? A: Pipeline.Supervisorone_for_one 策略)。 包含 Pipeline.Repo / Finch / Oban / Bandit。 Tags: ex-elixir

Q: Pipeline.Llm 行为 + 实现的”配置驱动多态”模式靠什么? A: Application.get_env(:pipeline, :llm, Pipeline.Llm.Real) 读配置。 默认 Real,要切 Dummy:Application.put_env(:pipeline, :llm, Pipeline.Llm.Dummy)。 Tags: ex-elixir

Q: Pipeline.Web 用什么 HTTP 服务器? A: Bandit({Bandit, plug: Pipeline.Web, port: 8002, ip: {127, 0, 0, 1}})。 绑 127.0.0.1(内部工具,无鉴权)。 Tags: ex-elixir

Q: Pipeline.Dag.graph/0 返回什么? A: %{nodes: [...], edges: [...]} —— 静态拓扑 + 每节点实时数据流入量。 前端 n8n 风格”网线”视图的数据源。 Tags: ex-elixir

Q: ex/elixir 的 Oban 失败任务怎么处理? A: POST /api/retry/:idOban.retry_job/2 重试。 GET /api/failedoban_jobs where state='discarded'。 Tags: ex-elixir


九、必背哲学口诀

Q: “Errors are values, not exceptions” 在 Elixir 中怎么实践? A: 预期失败返回 {:error, reason},不抛异常。 让调用方用 case / with 处理。 意外崩溃 → 让进程死,让 Supervisor 重启。 Tags: elixir-philosophy

Q: “Don’t write a macro if a function can do it” 含义? A: 能用函数就别用宏。宏难调试、难读。 宏的正当用途:定义 DSL(schematestuse)。 Tags: elixir-philosophy

Q: “Code is data” 在 Elixir 怎么体现? A: quote 把代码转 AST(三元组),unquote 把 AST 嵌回代码。 宏就是操作 AST 的函数。这是 Elixir 元编程的根基。 Tags: elixir-philosophy


CSV 导入格式(Anki 直接导入)

Q;A;Tags
"BEAM 进程初始内存大小?跟 Java Thread、goroutine 对比?";BEAM 进程 ~ 0.5 KB;goroutine ~ 2 KB;Java Thread ~ 512 KB。单机可创建百万级 BEAM 进程。;elixir-concurrency
"BEAM 调度是抢占式还是协作式?";抢占式——每 2000 reductions 强制切换。Go 的 goroutine 是协作式。;elixir-concurrency
"`use` vs `import` vs `require` vs `alias` 区别?";alias=模块别名;import=导入函数;require=让宏可见;use=调对方 __using__/1 宏注入代码;elixir-module
"协议(Protocol)跟 Java interface 的核心区别?";协议可以给已有类型加 dispatch,interface 不能扩展已存在类型;elixir-protocol
"99.999% 可用性选哪个语言?";Elixir / Erlang(30 年电信验证);elixir-selection