关于Elixir Keyword.merge/3函数键异常的技术问询
关于Elixir Keyword.merge/3重复键处理的答疑
这可不是异常行为哦,其实是Keyword.merge/3的设计特性——它对重复键的处理逻辑是分情况的,我给你拆解清楚:
核心规则拆解
Keyword.merge/3处理重复键时,会根据键是否同时存在于两个Keyword List来区分逻辑:
- 情况1:键同时出现在左右两个列表中
- 只取左列表中该键的第一个值,右列表中该键的第一个值,用你传入的合并函数处理,生成一个新的键值对放在结果里
- 把右列表中该键的所有后续重复项直接追加到结果中
- 左列表中该键的后续重复项会被直接丢弃!这就是你第一个例子里
{:a, 2}消失的原因
- 情况2:键只出现在左列表中
左列表中该键的所有项(包括重复项)都会原封不动保留在结果里 - 情况3:键只出现在右列表中
右列表中该键的所有项(包括重复项)都会原封不动追加到结果里
对应你的例子分析
第一个例子:两边都有:a和:b
输入代码:
iex> Keyword.merge([a: 1, a: 2, b: 2], [a: 3, b: 3, b: 4], fn _k, v1, v2->v1+v2 end) [a: 4, b: 5, b: 4]
处理过程:
- 处理
:a(两边都有):- 左列表第一个
:a的值是1,右列表第一个:a的值是3,合并后得到a:4并加入结果 - 右列表没有
:a的后续项,左列表的a:2被丢弃
- 左列表第一个
- 处理
:b(两边都有):- 左列表第一个
:b的值是2,右列表第一个:b的值是3,合并后得到b:5并加入结果 - 右列表的后续项
b:4被追加到结果
最终就得到了你看到的[a: 4, b: 5, b: 4]
- 左列表第一个
第二个例子::a只在左列表,:b两边都有
输入代码(补全你未写完的部分):
iex> Keyword.merge([a: 1, a: 2, b: 2], [b: 3, b: 4], fn _k, v1, v2->v1+v2 end) [a: 1, a: 2, b: 5, b: 4]
处理过程:
- 处理
:a(只在左列表):- 左列表的
a:1和a:2都被保留,直接加入结果
- 左列表的
- 处理
:b(两边都有):- 合并得到
b:5并加入结果 - 右列表的后续项
b:4被追加
所以{:a,2}会被完整保留在结果里
- 合并得到
总结
如果你的业务场景需要保留左列表中重复键的所有项(即使该键在右列表中存在),可能需要自己实现自定义合并逻辑,比如先合并唯一键,再手动遍历左列表追加重复项。但默认的Keyword.merge/3就是按照上述规则工作的,这是Elixir团队为平衡合并逻辑简洁性和常见使用场景设计的特性。
内容的提问来源于stack exchange,提问作者BlueGene
相关产品推荐
相关产品推荐

