【问题标题】:Pattern matching with a map inside a map (Elixir)与地图内的地图进行模式匹配(Elixir)
【发布时间】:2021-06-13 20:27:36
【问题描述】:

我在 Elixir 应用程序中具有以下功能:

  def emojify(%Conv{status: 200, resp_headers: resp_headers} = conv) do
    body = if resp_headers["Content-Type"] == "application/json", do: conv.resp_body, else: "????" <> "\n\n" <> conv.resp_body <> "\n\n" <> "????"
  
    %{ conv | resp_body: body }
  end

  def emojify(%Conv{} = conv), do: conv

我想对其进行重构,以消除其中对 if 的需求。我想这样做的方法是通过模式匹配resp_headers 内的内容类型,但这将是地图内地图的模式匹配(更准确地说是地图内的结构,但我不认为这个细节在这种情况下是相关的),我不知道该怎么做。

我正在尝试类似def emojify(%Conv{status: 200, resp_headers: %{"Content-Type" =&gt; "application/json"}} = conv) 的东西,但我知道这只有在resp_headers 里面只有"Content-Type" =&gt; "application/json" 时才有效,但事实并非如此。那我该怎么做呢?

【问题讨论】:

  • 请记住,HTTP 标头通常不区分大小写,也可能出现多次。因此,您使用的库实际上可能根本不使用映射,而是将它们包装在实现 Access 的结构中。
  • 现在,我只是从头开始构建东西以了解“Elixir 方式”,所以我没有使用库,也不是用于生产的应用程序。但很高兴知道,我会记住的!

标签: pattern-matching elixir


【解决方案1】:

我知道这只有在 resp_headers 里面只有 "Content-Type" =&gt; "application/json" 时才有效

这个假设是错误的。如果匹配中的字段显示在输入中,则映射匹配并且所有固定变量都匹配。你没有固定变量,所以你没问题。

经常使用匹配空映射而不是is_map(map)guard as foo(%{} = map) do ...

%{} = %{foo: 42, bar: :baz} # success

# and also
%{foo: foo} = %{foo: 42, bar: :baz} # success
foo
#⇒ 42

也就是说,答案是

def emojify(%Conv{
    status: 200,
    resp_headers: %{"Content-Type" => "application/json"}} = conv),
  do: %{ conv | resp_body: conv.resp_body }

def emojify(%Conv{status: 200} = conv),
  do: %{ conv | resp_body: "?" <> "\n\n" <> conv.resp_body <> "\n\n" <> "?"}

def emojify(%Conv{} = conv), do: conv

旁注: 带有固定变量的示例。

%{foo: 42} = %{foo: 42, bar: :baz} # success

foo = 42
%{foo: ^foo} = %{foo: 42, bar: :baz} # success

%{foo: ^foo} = %{foo: :incorrect, bar: :baz} # raises

【讨论】:

  • 只是指出以防有人怀疑:在def emojify(%Conv{status: 200} = conv) 中,返回值应该是映射%{ conv | resp_body: "?" &lt;&gt; "\n\n" &lt;&gt; conv.resp_body &lt;&gt; "\n\n" &lt;&gt; "?" }。但我明白了,它奏效了,谢谢!
  • 已在答案中修复,抱歉。
【解决方案2】:

你可以像这样进行模式匹配

def emojify( %{status: 200, resp_headers: %{"Content-Type" => "application/json" } } = conv
) do
    %{ conv | resp_body: conv.resp_body }    
   end
   def emojify(%{status: 200} = conv) do
    %{ conv | resp_body: "?" <> "\n\n" <> conv.resp_body <> "\n\n" <> "?" }
   end
   def emojify(conv), do: conv

您始终可以对映射或结构中特定键的值进行模式匹配

更多信息请查看joyofelixir

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-07
    相关资源
    最近更新 更多