簡體   English   中英

我可以在 Elixir 中重載 Map 的訂閱運算符嗎?

[英]Can I overload the subscription operator for Map in Elixir?

假設我有一個 map %{} ,其中的鍵是Decimal

有問題的是,在 Decimal 3.= 3.0中,因此,對 Decimal 鍵的索引是不可靠的,需要使用Decimal.eq?/2來測試相等性。

有沒有一種方法可以重載 map 訂閱運算符,以便 Decimal 上的索引實際使用eq? 相反==

mymap[Decimal.new(3)] == mymap[Decimal.from_float(3.0)]

如果我遺漏了另一種方法(例如協議/宏/其他東西,請告訴我!)

不幸的是,即使 Elixir 提供了許多擴展語言的方法(協議/宏...),映射是虛擬機提供的底層構造,您將無法覆蓋此行為。 映射需要依賴一些鍵的散列,而不僅僅是比較 function。

適用於您的用例的是首先使用Decimal.normalize/1規范化您的密鑰(在放置和訪問之前),以便兩者的密鑰相同:

iex> Decimal.new(3) |> Decimal.normalize()
#Decimal<3>
iex> Decimal.from_float(3.0) |> Decimal.normalize()
#Decimal<3>

您可以將其包裝在一個模塊中以進行頻繁操作:

defmodule DecimalMap do
  def put(map, key, value), do: Map.put(map, Decimal.normalize(key), value)
  def fetch(map, key), do: Map.fetch(map, Decimal.normalize(key))
  # ...
end
iex> map = DecimalMap.put(%{}, Decimal.from_float(3.0), "hello")
%{#Decimal<3> => "hello"}
iex> DecimalMap.fetch(map, Decimal.new(3))
{:ok, "hello"}

我認為這里有一些誤解。

  1. 據我所知,沒有“訂閱運營商”這樣的東西。 如果您指的是[] ,這就是Access 語法
  2. “十進制鍵的索引不可靠”。 Decimal是一種結構,結構通常帶有額外的語義,這意味着您不能依賴結構的底層底層形狀,您必須調用模塊中的函數 ( eq? ) 來提取含義。 如果您將Decimal用作 map 鍵,則隱含地依賴於它的結構而不是語義,這在這種情況下是無效的,因為不同的Decimal結構可以被認為在語義上是等價的。
  3. 由於floats 的不精確性, Decimal.from_float(3.0)不是一個精確的操作。 例如Decimal.from_float(0.3).= Decimal.from_float(0.1 + 0.2) 如果您的數據來自浮點數,您基本上無法比較它們是否完全相等,因為它們不精確,因此不應將它們用作鍵,也不應將它們與相等運算符(如==Decimal.eq? .

如果您只想將等效小數視為相等(解決上面的第 2 點,但不是第 3 點),您可以在將它們放入 map 之前對其進行歸一化:

Decimal.normalize(Decimal.new("3")) == Decimal.normalize(Decimal.new("3.0"))

但是,如果您從其他數據生成小數,這是一個危險的操作,因為不同的Decimal結構被認為是等價的。 例如,考慮以下 map:

map = %{Decimal.new("3") => "three", Decimal.new("3.0") => "three point zero"}

如果我們規范化鍵,我們將失去一個唯一值並得到違反直覺的響應:

Map.new(map, fn {k, v} -> {Decimal.normalize(k), v} end)
%{#Decimal<3> => "three point zero"}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM