请为多类型参数建议惯用的 Elixir

Please suggest idiomatic Elixir for multi typed arguments

我正在尝试改进我的 Elixir 库的代码,如下所示:

def dirs(path, regex_dir \ ".+") when (is_bitstring(path) or is_list(path)) do
  file_path = case String.valid? path do
    true -> [path]
    false -> path
  end
  do_dirs(file_path, [], regex_dir)
end

defp do_dirs([], result, regex_dir) do
  result
end

defp do_dirs(paths ,result, regex_dir) do
  [h | t] = paths
  do_dirs(t, result ++ dirs_list(h, regex_dir), regex_dir)
end

defp dirs_list(path, regex_dir) when is_bitstring(path) do
  Finder.new()
  |> Finder.with_directory_regex(Regex.compile!(regex_dir))
  |> Finder.only_directories()
  |> Finder.find(Path.expand(path))
  |> Enum.to_list
  |> Enum.sort
end

我特别讨厌检查 file_path 是否为有效字符串的部分,但我想不出一种方法来美化它或使它更符合 Elixir 的习惯。我希望 dirs 能够接受 bitstringlist 参数。

我会将规范化路径的部分提取到一个单独的方法中。它基本上需要处理两种情况:

  • 位串
  • bitstings 列表

但是,由于单引号字符串是作为字符列表实现的,当有人不小心将这样的值传递给您的库时,我发现了一个问题。它将被检测为一个列表,并可能导致库深处的错误,而不是给出有用的错误消息。这意味着您还需要处理以下两种情况:

  • 角色列表
  • 字符列表列表

我建议您在适当的地方尝试将潜在的字符列表转换为字符串。

def dirs(path, regex_dir \ ".+") do
  path
  |> normalize_path
  |> do_dirs([], regex_dir)
end

# list of bitstrings
defp normalize_path([path | rest]) when is_bitstring(path) do
  [path | normalize_path(rest)]
end

# list of character lists
defp normalize_path([path | rest]) when is_list(path) do
  [to_string(path) | normalize_path(rest)]
end

defp normalize_path([]) do
  []
end

# bitstring
defp normalize_path(path) when is_bitstring(path) do
  [path]
end

# character list
defp normalize_path(path) when is_list(path) do
  [to_string(path)]
end

它将进行以下转换:

normalize_path 'foo'             #=> ["foo"]
normalize_path "foo"             #=> ["foo"]
normalize_path ['foo', 'bar']    #=> ["foo", "bar"]
normalize_path ["foo", "bar"]    #=> ["foo", "bar"]
normalize_path ["foo", 'bar']    #=> ["foo", "bar"]
normalize_path ['foo', "bar"]    #=> ["foo", "bar"]