Elixir映射中相同值键名称上的模式匹配的快捷方式

时间:2017-06-01 06:02:48

标签: elixir

我在这种风格中做了相当多的模式匹配:

def action(%{start_date: start_date, amount: amount, notify: notify %}) do
  # some action
end

大多数情况下,我为参数选择的名称与地图中的名称相同。是否有指定模式匹配大小写的快捷方式,而不重复键和值的相同名称?

这段伪代码中的内容:

def action(%{start_date: %s, amount: %s, notify: %s}) do
  IO.inspect(start_date)
  # some action
end

2 个答案:

答案 0 :(得分:2)

AFAIK, there is nothing out of the box, but one could simply create a macro for themselves to serve that purpose:

defmodule M do
  defmacro struct(params) do
    {:%{}, [], Enum.map(params, fn e -> {e, {e, [], Elixir}} end)}
  end
end

defmodule Test do
  require M # to use macro
  def action(M.struct([:a, :b]) = params),
    do: IO.inspect params, label: "Params are"
end

Test.action(%{a: 42, b: :ok})
#⇒ Params are: %{a: 42, b: :ok}
Test.action(%{a: 42})
** (FunctionClauseError) no function clause matching in Test.action/1

The code above is of course just an MCVE, you probably need to enhance it somehow to handle corner cases more gracefully (and, probably, to have the more explicit readable macro that behaves smarter than just spitting the AST out, and considers the binding, etc,) but I believe that explains the idea.

答案 1 :(得分:1)

我引入了一个sigil ~m{...}来实现破坏性任务。

~m{foo bar} = %{foo: 1, bar: 2}
foo  #=> 1
bar  #=> 2

以下是我实施sigil的方法

defmodule DestructingAssignment do
  defmacro __using__(_) do
    quote do: import unquote(__MODULE__)
  end

  defmacro sigil_m({:<<>>, _line, [string]}, []) do
    spec = string
           |> String.split
           |> Stream.map(&String.to_atom/1)
           |> Enum.map(&{&1, {&1, [], nil}})
    {:%{}, [], spec}
  end
end

<强>用法

defmodule Foo do
  use DestructingAssignment

  def foo(~m{bar}) do
    # Do whatever you want with bar
    IO.inspect(bar)
  end
end

Foo.foo(%{bar: 1, baz: 2})
1