2016-07-06 22 views
11

我似乎無法找到一種方法來模擬函數頭中地圖上的鍵匹配。有沒有辦法做到這一點?我試圖做的是運行不同的代碼,具體取決於某個鍵是否已經存在於地圖中(也想避免if/else之類)如何在elixir中的函數頭中的地圖鍵上進行模式匹配

這就是我的代碼看起來像

def my_func(key, %{key => _} = map), do: ... 

這給了我這個錯誤

**(CompileError)地圖鑰匙匹配內非法使用可變密鑰的,地圖只能匹配使用^現有的可變密鑰

當然,我也嘗試過使用^

def my_func(key, %{^key => _} = map), do: ... 

,然後給

**(CompileError)綁定變量^鍵

我使用靈藥1.3.1/erlang 19.0 x64在Windows 8.1機器上。 感謝您的閱讀!

回答

12

只是模式匹配與你所需要的關鍵:

defmodule Test do 
    def my_func(%{"a" => value}), do: {:a, value} 
    def my_func(%{"b" => value}), do: {:b, value} 
    def my_func(_), do: :error 
end 

然後在IEx標誌:該條款的

iex(1)> Test.my_func(%{"a" => 1}) 
{:a, 1} 
iex(2)> Test.my_func(%{"b" => 2}) 
{:b, 2} 

此外依次是很重要的。例如,如果你試圖匹配%{"b" => 2}但有下列地圖%{"a" => 1, "b" => 2},關鍵"a"將首先匹配,因爲是第一個子句:

iex(3)> Test.my_func(%{"a" => 1, "b" => 2}) 
{:a, 1} 

如果你想生成的東西每個鍵可以匹配我推薦一種不同的方法。舉例來說,如果你要映射功能,這些按鍵:

defmodule Test0 do 
    def my_op({"times_2", value}), do: {"times_2", value * 2} 
    def my_op({"times_3", value}), do: {"times_3", value * 3} 
    def my_op({key, value}), do: {key, value} 

    def my_func(m) do 
    Enum.map(m, &my_op/1) |> Enum.into(%{}) 
    end 
end 

所以,你會得到如下:根據此答案的評論

iex(1)> Test0.my_func(%{"times_2" => 2, "times_3" => 3, "whatever" => 42}) 
%{"times_2" => 4, "times_3" => 9, "whatever" => 42} 

更新

你無法模式匹配變量的關鍵。問題是編譯器需要生成代碼來搜索它還不知道的東西。當你匹配模式時,你通常會給編譯器一些提示它會收到什麼。對於地圖中的鍵,提示是鍵本身。在這種情況下,即使指出第一個參數應該是查找的關鍵,但編譯器還不夠。所以你的方法應該是使用if語句:

defmodule Test2 do 
    def my_func(k, m) do 
    if Map.haskey?(k, m), do: warning(k, m), else: foo(k, m) 
    end 

    def warning(k, m) do 
    #Warning 
    m 
    end 

    # In this function you could apply the pattern matching 
    # described in the first part of this answer. 
    def foo(k, m) do 
    value = # do something 
    %{m | key => value} 
    end 
end 

我希望這能回答你的問題。

+0

嗨,謝謝你的回答。但我應該澄清一下'my_func(key,_)'中的鍵是運行時確定的變量,在編譯時不知道 – bottlenecked

+0

好吧,現在我已經部分地理解了你正在嘗試做什麼。你的函數究竟做了什麼? –

+0

嗯,我不認爲它是相關的添加函數體,但最終代碼將大致做到「如果鍵已經存在觸發警告,否則做富,並將其添加到地圖」 – bottlenecked

相關問題