副标题 / 摘要
可变值带来性能与直觉操作,不可变值带来安全与可预测性。本文从工程角度给出取舍指南。
目标读者
- 需要做语言/架构选型的开发者
- 经常处理共享状态与并发的工程师
- 想降低 bug 成本的团队负责人
背景 / 动机
“用可变还是不可变”常被当成风格问题,但本质是成本问题:
可变值降低了短期编码成本,却提高了长期维护成本;不可变值相反。
核心概念
- 可变值:对象可被修改,引用指向同一状态
- 不可变值:对象创建后不可变,修改通过创建新值
- 别名问题:多个引用指向同一对象导致隐式副作用
实践指南 / 步骤
- 核心业务规则优先用不可变
- 性能敏感且局部范围内用可变
- 共享数据优先不可变
- 用类型或约定明确边界
- 在接口处转换:可变在边界层,不可变在核心层
可运行示例
下面展示共享可变带来的副作用:
nums = [1, 2, 3]
ref = nums
ref.append(4)
print(nums) # [1, 2, 3, 4]
不可变方式:
nums = (1, 2, 3)
ref = nums
ref = ref + (4,)
print(nums) # (1, 2, 3)
print(ref) # (1, 2, 3, 4)
解释与原理
可变值让“状态变化”隐式发生,易产生别名问题;
不可变值把变化变成显式的新值,便于推理与测试。
常见问题与注意事项
不可变一定更慢吗?
不一定。结构共享与持久化数据结构可以降低成本。可变值是不是更直观?
对局部数据更直观,但对共享状态更危险。如何混用?
常见做法是“核心域不可变,边界层可变”。
最佳实践与建议
- 在并发场景优先不可变
- 在性能关键、局部封闭场景用可变
- 给团队建立明确的可变/不可变规范
小结 / 结论
可变值适合局部与性能场景,不可变值适合共享与核心逻辑。
真正的工程实践不是二选一,而是分层与约束。
参考与延伸阅读
- Effective Java:不可变对象章节
- Clojure Persistent Data Structures
- Rust Ownership Model
元信息
- 阅读时长:7~9 分钟
- 标签:可变性、不可变性、并发
- SEO 关键词:Mutable, Immutable, 并发安全
- 元描述:对比可变与不可变的优缺点,并给出工程选型建议。
行动号召(CTA)
列出你项目中最容易被“误修改”的对象,从把它变成不可变开始。