Elixir:如何处理函数中的可选/默认参数和nil值?
我有一个关于默认参数和nil值的一般性问题。假设我有两个函数。一个调用另一个(这是一个助手函数)。两者都有一个可选参数 helper函数只是用一个连接符将一个列表连接到一个字符串。joiner被传递给opts关键字列表中的第一个函数。joiner的传递是可选的,它默认为Elixir:如何处理函数中的可选/默认参数和nil值?,elixir,Elixir,我有一个关于默认参数和nil值的一般性问题。假设我有两个函数。一个调用另一个(这是一个助手函数)。两者都有一个可选参数 helper函数只是用一个连接符将一个列表连接到一个字符串。joiner被传递给opts关键字列表中的第一个函数。joiner的传递是可选的,它默认为和“ 问题是:在第二个示例中,opts[:joiner]将为零。但它仍然存在,因此不会使用默认值 一种可能的解决方案是使用案例: defmodule ParamTest do def func_1(list, opts \\
和“
问题是:在第二个示例中,opts[:joiner]将为零。但它仍然存在,因此不会使用默认值
一种可能的解决方案是使用案例
:
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
另一种方法是对helper使用两个函数定义,并使用模式匹配:
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
但我觉得这不是很优雅,在更复杂的情况下可能会变得混乱
对于这种情况,有什么更好的解决方案?在我看来,没有比您已有的更好的解决方案了。就我个人而言,我会问自己以下问题:
- 我确定需要
private函数的默认参数吗?我对此没有信心,但我觉得默认的helper/2
参数到私有函数可能是某种代码味道\\\
- 如果使用
默认参数,我想在哪里处理复杂性?:)李>\\
:joiner
选项的存在,分别调用helper/1
和helper/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
)可能是有意义的(取决于您的用例,这个太小了,我们无法做出更深思熟虑的决定:p):
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
同样,这在您的用例中可能无法很好地扩展,但我觉得这是我们从问题中获得的信息所能做的最好的:)。最好的解决方案是在helper中强制使用joiner,并在
func\u 1
中提供默认选项
def func_1(list, opts \\ [joiner: "AND"]) do
helper(list, opts[:joiner])
...
end
defp helper(list, joiner) do
...
end
总是试着把你的顾虑分开<代码>帮助程序不是公共API的一部分,因此您可以始终传递所有选项。让它只做它的工作,而不用担心默认值
func_1
是您的公共API,它应该担心默认设置。您希望在默认情况下指定“和”joiner,所以请这样做,而不是默认为空选项列表。当开发人员阅读您的代码时,他们不需要深入检查“AND”来自何处,并且可以很容易地确定,他们可以在不阅读文档甚至函数体的情况下传递此选项
在顶级函数(API)中使用默认值通常是一个好主意,只是为了方便起见,并且只需显式地向下传递所有内容。否则,您必须在每个级别进行检查,如果该选项像您在示例中使用
case
时那样被传递。这很容易出错。我同意私有函数的默认参数。我喜欢你的第二个解决方案。谢谢。如果只从第一个函数调用helper,那么使用双默认值是很尴尬的。第二种解决方案很尴尬,因为函数调用中有| |。您最好将默认值设置为opts\\\[joiner:”和“]@CaptChrisD,正如其他人在对另一个函数的评论中指出的那样,[joiner:”和“]
作为默认值通常不是一个好主意,因为该函数可以接受多个选项(很少函数只接受一个选项)。我甚至比@whatyouhide更喜欢你的版本,因为它让第一次阅读我代码的人非常清楚默认版本。谢谢,我不得不收回我先前的声明。随着opts参数传入更多选项,所有内容都将被覆盖,此解决方案将不再有效[“el 1”,“el 2”]|>parametest.func_1(某物:“任何”)
将生成“el 1 el 2”
您是对的。如果您有更多选项,并且只想覆盖其中的一些选项,选择[:joiner]| |”和“
更好。或者,在函数的第一行中,您可以执行opts=opts++[joiner:”和“]
,但这只有在所有选项都有默认值且存在两个默认值时才有意义。
def func_1(list, opts \\ [joiner: "AND"]) do
helper(list, opts[:joiner])
...
end
defp helper(list, joiner) do
...
end