修改哈希时Hash#merge与双splat运算符哪种性能更优
Ruby 哈希合并场景下
Hash#merge与双splat运算符(**)的性能对比 两种写法最终生成的新哈希结果完全一致,都不会修改原始哈希对象,核心差异体现在性能和适用场景上:
性能实测结论
在Ruby 2.5及以上所有主流稳定版本(含3.x系列)中,单哈希展开+少量键追加的场景下,双splat运算符性能明显优于Hash#merge,常规场景下性能领先幅度在20%~40%区间。
以下是基于Ruby 3.2版本、100万次执行的基准测试代码:
require 'benchmark' original_h = {a: 1, b: 2} test_loop_count = 1_000_000 Benchmark.bm do |x| x.report('double splat') { test_loop_count.times { {**original_h, c: 3} } } x.report('Hash#merge') { test_loop_count.times { original_h.merge(c: 3) } } end
典型测试输出参考:
user system total real double splat 0.172015 0.000000 0.172015 ( 0.172234) Hash#merge 0.258723 0.000000 0.258723 ( 0.258987)
性能差异原因
- 双splat是Ruby语法层面的原生特性,代码编译为AST阶段就会被优化为直接的哈希表内存拷贝、新键插入逻辑,没有额外的运行时方法调度开销。
Hash#merge是Hash类的实例方法,调用时需要经过方法查找、参数检查(该方法支持传入块自定义键冲突逻辑,即使不传块也会走完对应的分支判断),额外开销更高。
场景选择建议
- 仅做简单哈希合并、追加少量键、不需要自定义同键覆盖规则时,优先选双splat写法,性能更高,语法也更简洁。
- 存在以下需求时选择
Hash#merge(含原地修改的merge!版本)即可,无需纠结性能差异:- 需要自定义键冲突时的合并逻辑(比如同键值求和、取非空值等)
- 需要合并3个及以上哈希,连续双splat展开的性能优势会随哈希数量增加快速收窄,部分版本下甚至会低于merge
- 需要原地修改原有哈希对象而非生成新哈希
注意:Ruby 2.4及更早版本中双splat的实现存在性能缺陷,部分场景下速度反而慢于merge,这类已停止维护的旧版本不建议参考上述结论。
内容的提问来源于stack exchange,提问作者Sathish
相关产品推荐
相关产品推荐

