Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Elixir 长生不老药:十进制铸造,不允许负数_Elixir - Fatal编程技术网

Elixir 长生不老药:十进制铸造,不允许负数

Elixir 长生不老药:十进制铸造,不允许负数,elixir,Elixir,您好,我收到一个值,该值不能为负值,只能为正值。如果为负值,我想返回一个自定义错误,如果为负值,则转到管道 我现在有一个问题: def call(%{"id" => id, "value" => value}, operation) do Multi.new() |> Multi.run(:account, fn repo, _changes -> get_account(repo, id) end) |&

您好,我收到一个值,该值不能为负值,只能为正值。如果为负值,我想返回一个自定义错误,如果为负值,则转到管道

我现在有一个问题:

 def call(%{"id" => id, "value" => value}, operation) do
    Multi.new()
    |> Multi.run(:account, fn repo, _changes -> get_account(repo, id) end)
    |> Multi.run(:update_balance, fn repo, %{account: account} ->
      update_balance(repo, account, value, operation)
    end)
  end
  defp update_balance(repo, account, value, operation) do
    account
    |> operation(value, operation)
    |> update_account(repo, account)
  end
  defp operation(%Account{balance: balance}, value, operation) do
    value
    |> Decimal.cast()
    |> handle_cast(balance, operation)
  end

  defp handle_cast({:ok, value}, balance, :deposit), do: Decimal.add(balance, value)
  defp handle_cast({:ok, value}, balance, :withdraw), do: Decimal.sub(balance, value)
  defp handle_cast(:error, _balance, _operation), do: {:error, "Invalid operation!"}

正如我在上一篇评论中提到的,Decimal是一种不同的类型,它大于整数

幸运的是,Decimal提供了gt?,lt?并比较可以用来比较小数和整数的函数。为了尽可能少地修改代码,一个比较干净的解决方案是在handle_cast之前添加一个小的额外函数,并为handle_cast添加另一个定义。大概是这样的:

defp操作%Account{balance:balance},值,操作do 价值 |>小数点转换 |>也许是肯定的? |>操纵平衡、操作 终止 defp可能是正的?{:好的,值}do 大小写小数。比较?值,0 do :lt->{:错误,:负数} :gt->{:好的,值} 终止 终止 defp可能为正?错误,do:错误 defp句柄\u强制转换{:错误,:负数,\u平衡,\u操作do {:错误,数字必须为正} 终止 defp handle_cast{:确定,值},余额,:存款,do:Decimal.addbalance,值 ...
这样,如果它是一个负数,它将通过handle_cast的{:error,:negative_number}案例,如果它是正数或者由于某种原因转换失败,它将通过您已有的另一个handle_cast验证

,而@sbacarob的答案是完全正确的,为了方便起见,我将发布此消息

Decimal是一个函数,所以可以使用它的内部结构来处理负数。这将适用于现代版本的长生不老药≥ 1.11和检察官办公室≥ 二十三,

defguard是_decimal _positivevalue _mapvalue和 值.\uuuu结构\uuuu==十进制和 value.sign==1 有关详细信息,请参阅。并将其用作

defp操作%Account{balance:balance},值,操作do 价值 |>小数点转换 |>操纵平衡、操作 终止 defp handle_cast{:ok,value},balance 什么时候是十进制值, do:Decimal.addbalance,value 解除控制手柄\u投射\u错误,\u平衡,\u, do:{:错误,数字必须为正小数}
太好了,我要吃长生不老药! 欧盟金融机构助理和职能:

安置:


我试过这样做,但仍然接受负数,而且我还需要在检查负数之前转换为十进制。我用反完整代码编辑问题。如果我将值用作字符串,它仍然是负数,但如果我使用有效的数字。是的,如果是字符串,它将不起作用,因为字符串总是大于数字。2<3不会失败,但会返回false。我刚刚用更多的选项更新了答案是的,对不起。我正在更新答案。Decimal是一种不同的类型,和字符串一样,它也总是大于整数,这太神奇了!我没有意识到这一点,但肯定允许使用更干净的代码,而不需要太多的麻烦。嗯,我提供了一个本地支持警卫的程序。让我们看看。@Aleksei Matiushkin谢谢你伟大的解决方案,兄弟。
defmodule Rocketpay.Accounts.Operation do
  alias Ecto.Multi
  alias Rocketpay.Account

  def call(%{"id" => id, "value" => value}, operation) do
    fetch_account_operation_name = build_fetch_account_operation_name(operation)

    Multi.new()
    |> Multi.run(
      fetch_account_operation_name,
      fn repo, _previous -> fetch_account(repo, id) end
    )
    |> Multi.run(operation, fn repo, fetch_result ->
      account = Map.get(fetch_result, fetch_account_operation_name)

      update_balance(repo, account, value, operation)
    end)
  end

  defp fetch_account(repo, id) do
    case repo.get(Account, id) do
      nil -> {:error, "Account not found."}
      account -> {:ok, account}
    end
  end

  defp update_balance(repo, account, value, operation) do
    account
    |> calculate_new_balance(value, operation)
    |> update_account(account, repo)
  end

  defp calculate_new_balance(%Account{balance: balance}, value, operation) do
    value
    |> Decimal.cast()
    |> validate_greater_than_zero()
    |> handle_cast(balance, operation)
  end

  defp validate_greater_than_zero({:ok, casted_value}) do
    case Decimal.compare(casted_value, 0) do
      :lt -> :error
      :eq -> :error
      :gt -> {:ok, casted_value}
    end
  end

  defp validate_greater_than_zero(:error), do: :error

  defp handle_cast({:ok, valid_value}, balance, :deposit), do: Decimal.add(balance, valid_value)
  defp handle_cast({:ok, valid_value}, balance, :withdraw), do: Decimal.sub(balance, valid_value)

  defp handle_cast(:error, _balance, :deposit), do: {:error, "Invalid deposit value."}
  defp handle_cast(:error, _balance, :withdraw), do: {:error, "Invalid withdraw value."}

  defp update_account({:error, _reason} = error, _account, _repo), do: error

  defp update_account(new_balance, account, repo) do
    account
    |> Account.changeset(%{balance: new_balance})
    |> repo.update()
  end

  defp build_fetch_account_operation_name(operation),
    do: "fetch_#{operation}_account" |> String.to_atom()
end