ETS table - 将地图更新为记录

ETS table - Updating maps as records

示例代码:


defmodule Foo do

  def fast_cars_cache do
    fast_cars = 
    {
      %{color: "Red", make: "Mclaren", mileage: 15641.469},
      %{color: "Blue", make: "Ferrari", mileage: 120012.481},
      %{color: "Red", make: "Ferrari", mileage: 29831.021},
      %{color: "Black", make: "Ferrari", mileage: 24030.674},
      %{color: "Cobalt", make: "Ferrari", mileage: 412.811},
      %{color: "Blue", make: "Koenigsegg", mileage: 250.762},
      %{color: "Cobalt", make: "Koenigsegg", mileage: 1297.76}, 
      %{color: "Titanium", make: "Koenigsegg", mileage: 5360.336},
      %{color: "Blue", make: "Maserati", mileage: 255.78}
    }

    if Enum.member?(:ets.all(), :fast_cars_cache) do
      :ets.delete(:fast_cars_cache)
      :ets.new(:fast_cars_cache, [:duplicate_bag, :public, :named_table])
      :ets.insert(:fast_cars_cache, fast_cars)
    else
      :ets.new(:fast_cars_cache, [:duplicate_bag, :public, :named_table])
      :ets.insert(:fast_cars_cache, fast_cars)
    end
  end


  def update_record do
    fast_cars_cache()

    old_record = :ets.first(:fast_cars_cache)

    new_record = 
    %{color: "Black", make: old_record.make, mileage: 1641.469}

    :ets.delete(:fast_cars_cache, {old_record})
    |> IO.inspect(label: "Old record deleted")

    :ets.insert(:fast_cars_cache, {new_record})
    :ets.tab2list(:fast_cars_cache)
  end

end

输出:


iex(1)> Foo.update_record
Old record deleted: true
[
  {%{color: "Red", make: "Mclaren", mileage: 15641.469},
   %{color: "Blue", make: "Ferrari", mileage: 120012.481},
   %{color: "Red", make: "Ferrari", mileage: 29831.021},
   %{color: "Black", make: "Ferrari", mileage: 24030.674},
   %{color: "Cobalt", make: "Ferrari", mileage: 412.811},
   %{color: "Blue", make: "Koenigsegg", mileage: 250.762},
   %{color: "Cobalt", make: "Koenigsegg", mileage: 1297.76},
   %{color: "Titanium", make: "Koenigsegg", mileage: 5360.336},
   %{color: "Blue", make: "Maserati", mileage: 255.78}},
  {%{color: "Black", make: "Mclaren", mileage: 1641.469}}
]

Observations/Questions:

  1. 根据IO.inspectold_record被删除了,tab2list显示,这条记录仍然存在。这是为什么?
  2. 如果实际上 old_record 从未被删除,代码需要进行哪些调整才能完成此操作?
  3. 理想情况下,我想利用 :ets.select_replace(如果适用)一步完成此更新,但我无法确定 stipulations 的正面或反面符合规范要求。如果有人可以根据上面的示例用一两个示例来消除歧义,那将非常有帮助。

一如既往,非常感谢您的指导和建议:)

你应该清楚地区分映射和元组。 Map is a key-value structure. Tuple 不是。

:ets 记录是元组,不是映射。

您的初始结构是一个映射元组。一个元组,有很多映射。它作为单个元素插入到 :ets 中,这在您的输出中清晰可见(检查大括号。)

我猜你要将许多个元素插入到缓存中。

iex|1 ▶ :ets.new(:fast_cars_cache, [:duplicate_bag, :public, :named_table])
iex|2 ▶ fast_cars = [
...|2 ▶   {"Red", "Mclaren", 15641.469},
...|2 ▶   {"Blue", "Ferrari", 120012.481},
...|2 ▶   {"Red", "Ferrari", 29831.021}
...|2 ▶ ]
iex|3 ▶ :ets.insert(:fast_cars_cache, fast_cars)

:ets.first/1, as it’s stated in the documentation, returns the first key. :ets.detele/2 通过键 删除记录 并且您的代码将从 :ets.first/1 返回的任何内容包装到一个单元素元组中,使 :ets.delete/2 无论如何都是空操作(是的,:ets.delete/2 总是 returns true。)

iex|4 ▶ :ets.first(:fast_cars_cache)
#⇒ "Red"
iex|5 ▶ :ets.delete(:fast_cars_cache, {"Red"}) # NOOP
#⇒ true
iex|6 ▶ :ets.delete(:fast_cars_cache, "Red") # DELETED
#⇒ true

然后如果你想插入一条新记录,创建一个元组并插入它,不要创建一个包裹在单元素元组中的映射。要通过密钥获取旧记录,通常使用 :ets.lookup/2 或更复杂的 :ets.select.

iex|7 ▶ [{_, make, _}|_] = :ets.lookup(:fast_cars_cache, "Red")
iex|8 ▶ new_record = {"Black", make, 1641.469}
iex|9 ▶ :ets.insert(:fast_cars_cache, new_record)

我已经链接了足够多的文档,可以使用 :ets.select_replace/2 作为作业离开。