与地图内的地图进行模式匹配Elixir

问题描述

我在 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" => "application/json"}} = conv) 的东西,但我知道这只有在 resp_headers 内部只有 "Content-Type" => "application/json" 时才有效,但事实并非如此。那么我如何才能做到这一点?

解决方法

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

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

匹配空地图经常被用来代替is_map(map)守卫作为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
,

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

     cat  (max)score   fruit_color
cat                               
a      a        99.0  apple_yellow
b      b         9.0   apple_green
c    NaN         NaN           NaN
d    NaN         NaN           NaN
e    NaN         NaN           NaN
f    NaN         NaN           NaN
['none','red','yellow','green']

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

有关更多信息,请查看 joyofelixir