【问题标题】:Why would I use maps in Elixir为什么我要在 Elixir 中使用地图
【发布时间】:2019-11-04 06:09:25
【问题描述】:

过去几天我一直在学习 Elixir 的基础知识,虽然我不止一次读到新手很难决定使用哪种数据结构,但我个人并没有看到 Maps 之间有什么不同和结构。 我的意思是:

  • 要访问地图上的字段,我总是需要调用Map.fetch(@map, :field),而在结构上,我只需一个“。”即可轻松访问它。介于两者之间。

使用地图是否有性能原因?还是我对其他一些主要原因视而不见?因为总是调用Map.some_function 来处理映射的需要似乎比仅仅使用结构更冗长。

【问题讨论】:

    标签: elixir


    【解决方案1】:

    您关于需要使用Map 模块与地图交互的假设是不正确的。比如在iex中:

    iex(1)> foo = %{bar: "baz"}
    %{bar: "baz"}
    iex(2)> foo.bar
    "baz"
    iex(3)> foo = %{foo | bar: "other"}
    %{bar: "other"}
    

    这里我们创建一个映射,获取:bar 键,然后将值从"baz" 更新为"other",所有这些都使用内置语法。

    使用结构的原因是为了在编译时检查键。例如,如果我们定义一个带有键 foo 的结构:

    defmodule ExampleStruct do
      defstruct [:foo]
    end
    

    然后尝试使用密钥bar创建它:

    iex(1)> %ExampleStruct{bar: "baz"}
    ** (KeyError) key :bar not found
        (testy) expanding struct: ExampleStruct.__struct__/1
        iex:3: (file)
    

    我们收到一个错误,因为:bar 不是ExampleStruct 的有效密钥。使用地图,无需检查可以添加的键。

    【讨论】:

      【解决方案2】:

      结构只是关于可用键的契约的映射。让我们定义一个结构。

      iex> defmodule Alpha do
      ...>   defstruct [:a, :b, :c]
      ...> end
      

      那就用吧:

      iex> %Alpha{a: 3, b: 4, c: 5}
      %Alpha{a: 3, b: 4, c: 5}
      

      让我们创建一个类似的地图:

      iex> %{a: 3, b: 4, c: 5}
      %{a: 3, b: 4, c: 5}
      

      如果我们只是添加一个:__struct__ 键,我们会突然得到一个结构体:

      iex> %{__struct__: Alpha, a: 3, b: 4, c: 5}
      %Alpha{a: 3, b: 4, c: 5}
      

      . 语法适用于任何带有原子键的地图:

      iex> user = %{name: "Brett"}
      %{name: "Brett"}
      iex> user.name
      "Brett"
      

      但是如果你将它用于地图中不可用的键,你会得到一个错误:

      iex> user.age
      ** (KeyError) key :age not found in: %{name: "Brett"}
      

      如果结构有一组已定义的键,您可以更加确信您感兴趣的键是可用的。

      但是,在很多情况下,您希望以其他方式使用地图。它们允许您进行更有效的查找,而不是在您想要查找某些内容时随时迭代列表。

      【讨论】:

        【解决方案3】:

        Struct 只是一个底层的映射,带有名为__struct__ 的附加字段。创建地图时,您不能强制用户包含某些字段或为某些字段提供一些默认值,但您可以使用结构来做到这一点。除此之外,您可以使用结构和协议来实现数据多态性,即函数将根据结构类型被调用。一个示例场景是,如果您的应用程序上有用户,并且您宁愿使用 %User{}(下面的示例)结构和一些强制字段,如 namesurname,而不是依赖于 %{}(映射)。通过这种方式,您可以确保无论何时创建用户结构,您都将拥有 namesurname 字段,否则您将获得编译时错误。

        defmodule User do
           @enforce_keys [:name, :surname]
           defstruct [:name, :surname]
        end 
        

        https://elixir-lang.org/getting-started/structs.html

        【讨论】:

          【解决方案4】:

          我个人没有看到 Maps 和 Structs 之间有什么不同

          1. 如果您提前知道地图中的所有键,请使用结构。

          2. 如果您的地图需要存储不确定数量的键,请使用地图。例如,如果您正在读取一个 csv(逗号分隔值)文件,其中每一行都有两个值(一个潜在的键和一个映射中的值),但您正在读取的文件中的行数会有所不同,或者各个文件中的键值是不一样的,如果你想在map中输入这些键值对,那么你将无法使用结构体。

          默认情况下,我会选择一个映射,然后如果稍后您意识到您正在创建的映射的键始终相同,那么我会更改代码以使用结构。

          更让人迷惑的是,elixir 还有keyword lists,例如:

          [{:a, 1}, {:b, 2}]
          

          或等效的速记语法:

          [a: 1, b: 2]
          

          Elixir 提供了Keyword 模块用于访问值:

          ...该模块中的大多数函数的行为与字典完全相同 因此它们的工作方式与您在地图中找到的功能相似 模块。

          当您希望地图为同一个键存储多个值时,可以使用关键字列表;或者当您希望键/值对按特定顺序排列时。

          【讨论】:

            猜你喜欢
            • 2015-01-27
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-07-05
            • 2017-10-31
            相关资源
            最近更新 更多