2016-03-31 9 views
2

私は、デフォルトのパラメータとnil値に関する一般的な質問があります。私に2つの機能があるとします。一方は他方を呼び出す(これはヘルパー関数である)。どちらもオプションのパラメータを持っています。エリクシール:関数とnil値のオプション/デフォルトパラメータを扱うには?

ヘルパー関数は、リストをジョイナー付きの文字列に結合するだけです。結合子は、optsキーワードリスト内の最初の関数に渡されます。 "AND"

defmodule ParamTest do 
    def func_1(list, opts \\ []) do 
    helper(list, opts[:joiner]) 
    # Do something else with the result 
    end 

    defp helper(list, joiner \\ "AND") do 
    Enum.join(list, " #{joiner} ") 
    end 
end 

# Example 1 
["el 1", "el 2"] 
|> ParamTest.func_1(joiner: "AND") 
# Result "el 1 AND el 2" 

# Example 2 
["el 1", "el 2"] 
|> ParamTest.func_1 
# Result: "el 1 el 2" 
# But it should be also "el 1 AND el 2" 

にジョイナーの通過はオプションであり、それはデフォルトの問題がある:オプト[:ジョイナー]は第二例ではゼロであろう。しかし、まだ存在しているので、デフォルト値は使用されません。

一つの可能​​な解決策を使用することですcase

defmodule ParamTest do 
    def func_1(list, opts \\ []) do 
    case is_nil(opts[:joiner]) do 
     true -> helper(list) 
     false -> helper(list, opts[:joiner]) 
    end 
    # Do something else with the result 
    end 

    defp helper(list, joiner \\ "AND") do 
    Enum.join(list, " #{joiner} ") 
    end 
end 

もう一つの方法は、ヘルパーのための2つの関数定義を使用して、パターンマッチングを使用することです:

defmodule ParamTest do 
    def func_1(list, opts \\ []) do 
    case is_nil(opts[:joiner]) do 
     true -> helper(list) 
     false -> helper(list, opts[:joiner]) 
    end 
    end 

    defp helper(list, nil) do 
    Enum.join(list, " AND ") 
    end 

    defp helper(list, joiner \\ "AND") do 
    Enum.join(list, " #{joiner} ") 
    end 
end 

をしかし、私はこのような感じを持っています非常にエレガントではなく、より複雑な状況で乱雑になる可能性があります。

このシナリオではどのような解決策がありますか?

答えて

1

私の意見ではあなたがすでに持っているものより良い解決策はありません。個人的に、私は自分自身を尋ねる次の質問:

  • は私がhelper/2プライベート関数のデフォルト引数を必要と私は確信していますか?私はこれに自信がないが、私はデフォルトのように感じる\\プライベート関数への引数は、コードのいくつかの種類のにおいがあります。
  • \\デフォルト引数を使用すると、どこで複雑さを処理したいですか? :)

私が選択しなければならなかった場合は、この特定のケースでは、私はおそらく:joinerオプションの存在に基づいて、個別にhelper/1helper/2を呼んでいいと思う:

defmodule ParamTest do 
    def func_1(list, opts \\ []) do 
    if joiner = opts[:joiner] do 
     helper(list, joiner) 
    else 
     helper(list) 
    end 
    end 

    defp helper(list, joiner \\ "AND") do 
    Enum.join(list, " #{joiner} ") 
    end 
end 

しかし、私のように上記のように、helper/2はプライベート関数なので、オプションのジョイナを "システム"の境界まで完全に移動するには、あなたのユースケースに応じて、これは小さすぎます。つまり、オプションのデフォルト値を使用してfunc_1/2にちょうどです:

defmodule ParamTest do 
    def func_1(list, opts \\ []) do 
    helper(list, opts[:joiner] || "AND") 
    end 

    defp helper(list, joiner) do 
    Enum.join(list, " #{joiner} ") 
    end 
end 

また、これはユースケースではうまく調整できないかもしれませんが、質問から得られた情報でできることは最高の気分です:)。

+0

私はプライベート関数のデフォルト引数に同意します。そして私はあなたの2番目の解決策が好きです。ありがとう。 –

+0

ヘルパーが最初の関数からのみ呼び出される場合は、二重のデフォルトを持つことは厄介です。第2の解決策はあなたが||関数呼び出しの中で。他の人がコメント内で他の関数に指摘しているように、あなたのデフォルトのoptsを\\ [joiner: "AND"] – CaptChrisD

+0

@CaptChrisDとする方が良いでしょう。デフォルトでは '[joiner:" AND "]'関数が多くのオプションを受け入れることができるので、良い考えではありません(関数が1つのオプションしか受け付けないことはまれです)。 – whatyouhide

5

最良の解決策は、joinerをヘルパーで必須にして、func_1にデフォルトオプションを提供することです。

def func_1(list, opts \\ [joiner: "AND"]) do 
    helper(list, opts[:joiner]) 
    ... 
end 
defp helper(list, joiner) do 
    ... 
end 

常にあなたの懸念事項を分けてください。 helperはパブリックAPIの一部ではないため、常にすべてのオプションを渡すことができます。それは単に仕事をして、デフォルトについて心配しないでください。

func_1は公開APIであり、デフォルトについて心配する必要があります。デフォルトでは "AND"ジョイナを指定したいので、空のオプションリストをデフォルトにする代わりにそれを行います。誰かがあなたのコードを読んでいるとき、彼は "AND"がどこから来たのかを簡単に理解する必要はなく、ドキュメントや機能の本体を読まなくてもこのオプションを渡すことができます。

トップレベル関数(API)の便宜のためにデフォルトを設定し、明示的にすべてを明示的に渡すことは、通常はお勧めします。それ以外の場合は、各レベルで、caseを使用しているようにオプションが渡されたかどうかをチェックする必要があります。これはエラーが発生しやすいです。

+0

私はあなたのバージョンが@whatyouhideによるものよりもさらに好きです。なぜなら、初めて自分のコードを読んでいる人にとって、デフォルトを非常にはっきりさせるからです。ありがとうございます –

+0

私は前の声明を取り下げなければなりません。 opts引数でより多くのオプションが渡されると、すべてが上書きされ、この解決策はもう機能しません。 '' el 1 "、" el 2 "] |> ParamTest.func_1(何か:"何でも ")' 'el 1 el 2" 'を生成します –

+0

あなたは正しいです。場合によっては、より多くのオプションがあり、それらのうちのいくつかだけを無効にしたい場合は、 'opts [:joiner] || 「AND」が良いです。あるいは、最初の関数行で 'opts = opts ++ [joiner:" AND "]'を実行することもできますが、これはすべてのオプションにデフォルトがあり、それらの組み合わせが2つある場合にのみ意味があります。 – tkowal

関連する問題