【问题标题】:This clause cannot match because a previous clause always matches此子句无法匹配,因为前一个子句始终匹配
【发布时间】:2016-04-15 02:32:25
【问题描述】:

不知道为什么我会收到此编译器警告。我在这里做错了什么?

defmodule T do
    def get_length do
        with {:ok, file} <- File.read("<file>"),
             content <- String.downcase(file) do
                IO.puts content
             end
    end
end

警告:此子句无法匹配,因为第 4 行的前一个子句始终匹配

【问题讨论】:

  • 文件的第 4 行与此代码 sn-p 的第 4 行不同 - 您可以输入适当的行号或发布整个文件吗?
  • 嗨@CodyPoll。已更新。
  • 仅供参考,如果我在 Elixir shell 中运行它,我不会收到警告。但是,如果我从命令行运行,那么我会这样做。
  • 确实在 iex 中收到警告(我假设您所说的“Elixir shell”就是这个意思)。
  • 是的,我的意思是 iex。真的吗?我没有使用 1.2.4 版

标签: elixir


【解决方案1】:

TLDR:with 这里有点矫枉过正。

defmodule T do
  def get_length do
    {:ok, file} = File.read("<file>") 
    IO.puts String.downcase(file)
  end
end

另外,您会收到编译器警告,因为content 将有效匹配String.downcase/1 提供的任何内容。

详细模式:

我认为你不明白with 的意图。 with 是通过描述您关心的快乐路径上的模式匹配来将许多复杂的嵌套案例链接在一起的糖。

因此,不必写像这样令人发指的东西......

defp serve(socket) do
  msg =
    case read_line(socket) do
      {:ok, data} ->
        case KVServer.Command.parse(data) do
          {:ok, command} ->
            KVServer.Command.run(command)
          {:error, _} = err ->
            err
        end
      {:error, _} = err ->
        err
    end

  write_line(socket, msg)
  serve(socket)
end

...你可以写出这个可爱的魔法:

defp serve(socket) do
  msg =
    with {:ok, data} <- read_line(socket),
         {:ok, command} <- KVServer.Command.parse(data),
         do: KVServer.Command.run(command)

  write_line(socket, msg)
  serve(socket)
end

因此,为了好玩,让我们根据您的文件示例来创建一个可以使用with 的情况。

想象一下这里定义的函数有相当复杂的失败案例

defmodule X do
  def extract_header(file) do
    # returns {:ok, file} or {:err, file} or whatever
  end

  def starts_with_emoji?(file) do
    # returns true or false
  end
end

你可以看到with如何派上用场:

defmodule T do
  def header_emoji_alert do
    with {:ok, file} <- File.read("<file>"),
         {:ok, header} <- X.extract_header(file),
         true  <- X.starts_with_emoji?(header), do: IO.puts("EMOJI!!!!")
  end
end

【讨论】:

  • 这里有点难以说出他的(不定代词意义)意图。
  • 是的,我确实提出了一个简单的案例。我知道这是一条幸福的道路。我的目标是习惯使用 with,因为我喜欢它的流畅性。那么我收到编译器警告是因为我只是将它用于一条快乐的道路吗?
  • 感谢您的解释。这说得通。我只是被警告吓跑了。
  • 编译器警告很明显:模式应该匹配可能值的子集。 content &lt;- String.downcase(whatever) 匹配您提供的任何内容,因为内容未定义。由于匹配没有达到目的,您会收到错误消息。
【解决方案2】:

你真的打算这样做吗?

defmodule T do
   def get_length do
     with {:ok, file} <- File.read("<file>") do
       content = String.downcase(file) #Assigning result of String.downcase  will _always_ work.
       IO.puts content
     end
   end
 end

说实话,推断代码的意图有点困难。我的意思是这也会做同样的事情(据我所知)

defmodule T do
   def get_length do
     {:ok, file} = File.read("<file>") 
     content = String.downcase(file)
     IO.puts content
   end
 end

我的意思是说我不确定在哪里使用with 可以在这里获得什么。

在 Erlang 和 Elixir 中,如果您从 File.read 返回除 {:ok, file} 元组以外的任何内容,就会抛出错误,这是一种惯用的做法。如果您无法读取该文件,那么真的没有恢复选项吗?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-16
    • 2021-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-12
    • 1970-01-01
    • 2023-02-20
    相关资源
    最近更新 更多