You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否重载Elixir中Map的订阅运算符以适配Decimal键?

用Decimal作为Map键的相等性处理方案

首先明确:没法直接重载Map的订阅运算符[],Elixir的内置Map结构中,[]的键匹配逻辑固定基于==,无法修改这个行为。不过有几个可行的替代方案:

1. 自定义包装模块封装Map操作

自己写一个模块,把Map的读写操作封装起来,内部用Decimal.eq?/2判断键的相等性:

defmodule DecimalMap do
  def new, do: %{}

  # 存入键值对时,先移除逻辑相等的旧键
  def put(map, key, value) when is_map(map) and is_struct(key, Decimal) do
    existing_key = Enum.find(map, fn {k, _} -> Decimal.eq?(k, key) end)
    map = if existing_key, do: Map.delete(map, elem(existing_key, 0)), else: map
    Map.put(map, key, value)
  end

  # 读取时用Decimal.eq?匹配键
  def get(map, key) when is_map(map) and is_struct(key, Decimal) do
    Enum.find_value(map, fn {k, v} -> Decimal.eq?(k, key) && v end)
  end
end

用法示例:

map = DecimalMap.new()
map = DecimalMap.put(map, Decimal.new(3), "three")
DecimalMap.get(map, Decimal.from_float(3.0)) # 返回 "three"

2. 用宏简化查找逻辑

写一个宏,把对Decimal键的查找自动转换成基于Decimal.eq?的遍历,不用每次手动写Enum.find:

defmodule DecimalMapMacro do
  defmacro dm_get(map, key) do
    quote do
      Enum.find_value(unquote(map), fn {k, v} ->
        cond do
          is_struct(k, Decimal) and is_struct(unquote(key), Decimal) ->
            Decimal.eq?(k, unquote(key)) && v
          true ->
            k == unquote(key) && v
        end
      end)
    end
  end
end

用法示例:

import DecimalMapMacro

map = %{Decimal.new(3) => "three"}
dm_get(map, Decimal.from_float(3.0)) # 返回 "three"

3. 预规范化Decimal键

存入Map前,对所有Decimal键做规范化处理,让逻辑相等的Decimal变成结构上==相等的实例,这样就能直接用Map的默认订阅运算符:

# 用Decimal.normalize/1规范化键
key1 = Decimal.new(3) |> Decimal.normalize()
key2 = Decimal.from_float(3.0) |> Decimal.normalize()

map = %{key1 => "three"}
map[key2] # 返回 "three",因为规范化后两个结构体==相等

注意:这个方案依赖Decimal.normalize/1的效果,大部分场景下能让逻辑相等的Decimal统一结构,但如果涉及特殊精度配置,可能需要额外调整规范化规则。

内容的提问来源于stack exchange,提问作者cjm2671

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 12:45:43