我正在学习Elixir并且有点困惑为什么我们必须使用相同函数的多个定义进行分支,而不是使用case语句.以下是来自Elixir in Action的第一版第81页的示例,用于计算文件中的行:
defmodule LinesCounter do
def count(path) do
File.read(path)
|> lines_num
end
defp lines_num({:ok, contents}) do
contents
|> String.split("\n")
|> length
end
defp lines_num({:error, _}), do: "error"
end
Run Code Online (Sandbox Code Playgroud)
所以我们有两个defp lines_num实例来处理以下情况:ok和:error.但是,以下是不是做同样的事情,可以说是更清洁,更简洁,只使用一个函数而不是三个?
defmodule LinesCounterCase do
def count(file) do
case File.read(file) do
{:ok, contents} -> contents |> String.split("\n") |> length
{:error, _} -> "error"
end
end
end
Run Code Online (Sandbox Code Playgroud)
两者的工作方式相同.
我不想学习不正确的习语,因为我开始了Elixir的旅程,所以澄清以这种方式使用case语句的缺点,就是我在寻找的东西.
tko*_*wal 15
书中的代码不是很惯用,它试图在不是最好的例子上显示多个函数子句和管道.
首先,一般约定说管道应该以"raw"变量开头,如下所示:
def count(path) do
path
|> File.read
|> lines_num
end
Run Code Online (Sandbox Code Playgroud)
第二件事是这个代码真的混合了责任.有时对函数返回的类型也有好处.如果我看到,lines_num返回整数或字符串,我真的会抓住我的头.lines_num阅读文件时为什么要关心错误?答案是:它不应该.它应该采用一个字符串并返回它计算的内容:
defp lines_num(contents) do #skipping the tuple here
contents
|> String.split("\n")
|> length
end
Run Code Online (Sandbox Code Playgroud)
现在,您的计数功能有两个选项.当文件出现问题或处理错误时,您可以让它崩溃.在这个例子中只返回字符串"error",所以最惯用的方法是完全跳过它:
def count(path) do
path
|> File.read! #note the "!" it means it will return just content instead {:ok, content} or rise an error
|> lines_num
end
end
Run Code Online (Sandbox Code Playgroud)
Elixir几乎总是提供func!版本,正是出于这个原因 - 使管道更容易.
如果要处理错误,case语句是最好的.Unix管道也不鼓励分支.
def count(path) do
case File.read(path) do
{:ok, contents} -> lines_num(contents)
{:error, reason} -> do_something_on_error(reason)
end
end
Run Code Online (Sandbox Code Playgroud)
有两种主要情况,其中多个函数子句优于case语句:递归和多态.还有其他一些,但对初学者来说应该足够了.
假设你想使lines_num更通用的也处理chars表示列表:
defp lines_num(contents) when is_binary(contents) do
...
end
defp lines_num(contents) when is_list(contents) do
contents
|> :binary.list_to_bin #not the most efficient way!
|> lines_num
end
Run Code Online (Sandbox Code Playgroud)
实现可能会有所不同,但最终结果将是相同的:不同类型的行数:"foo \n bar"和'foo \n bar'.
def factorial(0), do: 0
def factorial(n), do: n * factorial(n-1)
def map([], _func), do: []
def map([head, tail], func), do: [func.(head), map(tail)]
Run Code Online (Sandbox Code Playgroud)
(警告:示例不是尾递归的)使用这种函数的情况将更不易读/惯用.
| 归档时间: |
|
| 查看次数: |
2955 次 |
| 最近记录: |