“ with”运算符中的逻辑条件不起作用

问题描述 投票:0回答:3

我有此代码:

  def edit(conn, params) do
    with m1 <- Repo.get(Model1, params["model1_id"]),
      m2 <- Repo.get(Model2, params["model2_id"]),
      !is_nil(m1) and !is_nil(m2)
    do
      # 1
      res = !is_nil(m1) and !is_nil(m2)
      IO.puts("***** res: #{res}")                              # ===> false

      IO.puts("***** m1: #{Kernel.inspect(m1)}")                # ===> prints a struct
      IO.puts("***** m1 is_nil: #{is_nil(m1)}")                 # ===> false

      IO.puts("***** m2: #{Kernel.inspect(m2)}")                # ===> nil
      IO.puts("***** m2 is_nil: #{is_nil(m2)}")                 # ===> true

    else
      #2
      _ -> raise ArgumentError, "not found"
    end
  end

即使m2为零,流#1也被执行。怎么会这样?如何解决?目标-确保m1和m2不为零,然后执行流程#1。

elixir ecto
3个回答
0
投票

with

with表达式严格用于模式匹配。它不是if-else条件的“可链接替代”。

基本上with将遍历您的所有子句,并尝试将其与<-箭头的左侧进行模式匹配。当第一个模式匹配失败(不匹配)时,它将仅执行error子句中的一个。

您的代码存在问题

with中的第三行是!is_nil(m1) and !is_nil(m2),即使表达式本身等于false,也总是会成功进行模式匹配。

修复

要使代码执行您实际想要的操作,应在第三行添加左侧,以便强制其进行模式匹配:

with m1 <- Repo.get(Model1, params["model1_id"]),
      m2 <- Repo.get(Model2, params["model2_id"]),
      {true, true} <- is_nil(m1) and is_nil(m2) do
 ...

惯用药剂

[为了使代码更加通用,您还可以使用Guards,允许使用is_nil。这将使您的代码看起来像:

with m1 when not is_nil(m1) <- Repo.get(Model1, params["model1_id"]),
      m2 when not is_nil(m2) <- Repo.get(Model2, params["model2_id"]) do
 ...

更好的可读性

最后一个技巧是始终专注于可读性。您正在编写供人类阅读的代码,因此,在线上发生的事件较少,通常更易于阅读。

您的代码将更具可读性:

m1 = Repo.get(Model1, params["model1_id"])
m2 = Repo.get(Model2, params["model2_id"])

with m1 when not is_nil(m1) <- m1,
      m2 when not is_nil(m2) <- m2 do
 ...

您真的需要with吗?

您的with除了确保m1m2不是nil外,什么也不做。也可以轻松地使用caseif完成此操作,因为在这里实际上不需要任何模式匹配:

m1 = Repo.get(Model1, params["model1_id"])
m2 = Repo.get(Model2, params["model2_id"])

if !is_nil(m1) && !is_nil(m2) do
 ...

2
投票

[Kernel.SpecialtForms.with/1“仅当该子句中没有匹配项时才返回”。


0
投票

[我发现自己仅在特定情况下使用if Repo.get(Model1, params["model1_id"]) && Repo.get(Model2, params["model2_id"]), do: ... ,在这些情况下它确实有帮助,主要是在一些类似于“管道”的操作集合中,例如,您需要下一个步骤的前一个结果,但是确实是异构的,您没有或没有必要创建一些令牌结构来保存转换和错误(类似于ecto变更集)。

© www.soinside.com 2019 - 2024. All rights reserved.