Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Elixir地图中相同值键名称的模式匹配快捷方式_Elixir - Fatal编程技术网

Elixir地图中相同值键名称的模式匹配快捷方式

Elixir地图中相同值键名称的模式匹配快捷方式,elixir,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 I

我以这种风格进行了大量的模式匹配:

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

好了,没有现成的东西,但是可以简单地为自己创建一个宏来达到这个目的:

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

上面的代码当然只是一个MCVE,您可能需要以某种方式对其进行增强,以更优雅地处理角落案例(并且,可能有一个更明确的可读宏,它的行为比吐出AST更智能,并考虑绑定等),但我相信这就解释了这个想法。

我引入了一个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

依我拙见,这保留了一些角色,但也带来了一定程度的含蓄。在您给出的单个示例中,这可能并不明显,但随着这种含蓄性的增加,代码变得难以阅读,需要更多的间接思考。保持代码清晰,并为增加字符付出代价。@smos“间接思维”的定义取决于对你来说什么是“直接的”以及你的习惯是什么。有时,当涉及到许多要显式匹配的map成员时,它会变得嘈杂,需要更多的“间接阅读”。我从来没有为此使用过任何短缺/语法糖,但我可以很容易地想到一些情况,在这些情况下,这很有意义。例如,module声明了一组宏,目的只有一个:关闭函数定义中的噪音。仅供参考,用
~m
符号完成类似的操作。@mudasobwa我完全同意你文章的部分内容。它有时有助于隐藏一些细节,使其具有声明性和更明确的含义。例如,示例
whatyouhide
poset实现了在使用赋值进行匹配时非常直观的功能。人们可以猜测,到底发生了什么。在函数声明中,我必须查找它,或者通过谷歌来了解它的功能。在这一点上,我愿意接受一些代码干扰。为什么要将
导入
别名为
使用
?显式导入销毁分配有什么问题?这看起来有点误导,尽管它在键入时节省了3个字符:)因为否则您必须
要求销毁分配
(因为该符号是一个宏,而不是一个函数),然后
导入销毁分配
<代码>使用将隐式地
首先要求
模块。
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