【问题标题】:Pattern Matching Against Records as Tuples in Erlang (Elixir)在 Erlang (Elixir) 中对作为元组的记录进行模式匹配
【发布时间】:2014-01-11 00:57:57
【问题描述】:

在 Erlang(或 Elixir)中将记录作为元组进行模式匹配是一种不好的做法吗?

示例代码:假设我们已经定义了这个模块:

defmodule Ween do
  defrecord TimeSpot, at: nil, tag: nil

  def proper?({ _, _, "home"} = v),   do: { true,   "succeeded with:  #{inspect v}"     }
  def proper?(other),                 do: { false,  "failed with:     #{inspect other}" }

  def sample, do: TimeSpot.new(tag: "home")
end

如果我们定义一个测试如下:

defmodule WeenTest do
  use ExUnit.Case
  require Ween

  test "records are tuples" do
    case Ween.proper?(Ween.sample) do 
      { true, v }       ->  IO.puts v
                            assert(true)
      { false, v }      ->  IO.puts v
                            assert(false)
    end
  end
end

会成功的。

编辑 1:@parroty 这里对测试的元组进行模式匹配的原因是为了模拟某种“某种”鸭子类型的记录;我希望的最终结果应该是这样的:

defmodule Ween do
  defrecord TimeSpot, at: nil, tag: nil

  def proper?([tag: "home"] = v),          do: { true,   "succeeded with:  #{inspect v}"     }
  def proper?([tag: "1234"] = v),          do: { true,   "succeeded with:  #{inspect v}"     }
  def proper?(other),                      do: { false,  "failed with:     #{inspect other}" }

  def sample, do: TimeSpot.new(tag: "home")
end

因此,带有“标签”字段且带有“home”值的每条记录都将匹配第一个子句。当然,那里似乎会有一些性能损失。

【问题讨论】:

    标签: erlang pattern-matching tuples record elixir


    【解决方案1】:

    只是为了完整性(因为这个问题在 Elixir 标记问题列表中仍然很高):从 Elixir 0.13 开始,不推荐使用记录(除了与 Erlang 代码交互),现在最好使用 Structs 来实现这个问题。这些也方便地为您提供所需的多态性(结构是 Map 的一种形式)

    http://elixir-lang.org/getting_started/15.html
    

    【讨论】:

    • 这些 Map 与 Erlang R17 中引入的 Map 相同还是不同?
    • 有点。实际上,思想链似乎是 Records 鼓励以 OO 样式在记录中添加功能(就像您所做的那样),而“elixir/erlang 方式”是鼓励功能方法。因此,“字典”作为协议被引入。那么“Map”是使用 E17 Map 类型的 Dict 协议的实现。但是,这种实现被声明为“对于少量值来说很快,但对于大量值来说很慢”,因此还有一种“HashDict”类型应该用于大量键......
    • 然而,Struct 是 Map 的一种最小实现,它不提供 Dict 协议特性,即对于所有实际效果,它是一种基本的哈希类型。这似乎是“类类型”的骨干所需要的(不是正确的词,但希望你明白我的意思)。最新的发展(我认为是 Elixir 0.14)是我们可以拥有您可以包含的实现。结果是,您可以从基本的“结构”开始,如果您想要该功能,可以包含 Enumerable 位......酷
    【解决方案2】:

    我认为记录可以直接用于模式匹配(这会比使用元组结构更好)。

    defmodule Ween do
      defrecord TimeSpot, at: nil, tag: nil
    
      def proper?(TimeSpot[tag: "home"] = v),  do: { true,   "succeeded with:  #{inspect v}"     }
      def proper?(other),                      do: { false,  "failed with:     #{inspect other}" }
    
      def sample, do: TimeSpot.new(tag: "home")
    end
    

    【讨论】:

      【解决方案3】:

      Cesarini 和 Thompson 在他们的书Erlang Programming 中说,永远不要依赖记录作为元组实现的事实,因为这种实现可能会改变。请参阅this question 的已接受答案。

      【讨论】:

      • 另一个原因是您可能想要更改记录定义(例如添加一个新字段),在这种情况下,需要修改直接模式匹配,而 Parroty 解决方案仍然很好。恕我直言,这是使用记录而不是元组的原因,所以这就是为什么不使用记录的直接模式匹配很重要。
      • 实际上他们过于谨慎了,记录被定义为元组,其中第一个元素是记录名称,然后按照与记录中相同的顺序跟随记录字段定义。然而,混合记录语法和元组语法被认为是一种不好的风格,因为它消除了使用记录的主要好处之一。
      猜你喜欢
      • 2013-06-25
      • 2018-01-08
      • 2015-05-06
      • 2020-09-18
      • 1970-01-01
      • 1970-01-01
      • 2018-03-16
      • 2014-07-04
      • 2011-11-10
      相关资源
      最近更新 更多