Elixir-将字符串数字或空字符串转换为float或nil

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

我正在尝试将price字段(它是一个字符串(例如"2.22""")转换为float或nil,然后将其添加到数据库中。

  def insert_product_shop(conn, product_id, shop_id, price) do
    priceFloat = nil
    if price not in [""] do
      price = elem(Float.parse(price), 0)
      priceFloat = price / 1
      IO.inspect(priceFloat)
    else
      priceFloat = nil
    end
    IO.inspect(priceFloat)
    changeset = Api.ProductShop.changeset(%Api.ProductShop{
      p_id: product_id,
      s_id: shop_id,
      price: priceFloat,
      not_in_shop_count: 0,
      is_in_shop_count: 0
      })
    errors = changeset.errors
    valid = changeset.valid?
    IO.inspect(changeset)
    case insert(changeset) do
      {:ok, product_shop} ->
        {:ok, product_shop}
      {:error, changeset} ->
        {:error, :failure}
    end
  end

输出为:

2.22
nil
#Ecto.Changeset<action: nil, changes: %{}, errors: [], data: #Api.ProductShop<>,
 valid?: true>

13:25:41.745 [debug] QUERY OK db=2.0ms
INSERT INTO "product_shops" ("is_in_shop_count","not_in_shop_count","p_id","s_id") VALUES ($1,$2,$3,$4) RETURNING "id" [0, 0, 40, 1]

如输出所示,priceFloat变为零,我认为是因为当我将其设置为2.22时,它不在范围内。也许我的代码太必要了。如何重写此代码以将“ 2.22”转换为2.22,而不使其变为nil,并允许将“”转换为nil?

elixir ecto elixir-framework
4个回答
1
投票

您可以使用case来评估Float.parse的返回值,并在返回nil时分配:error,前提是if的目的是避免解析错误

def insert_product_shop(conn, product_id, shop_id, price) do
  priceFloat = case Float.parse(price) do
    {value, _remainder} -> value
    :error -> nil
  end
  ...
end

2
投票

如输出所示,priceFloat变为nil,因为我将其设置为2.22时超出了范围。

几乎正确。问题在于,您要设置的变量不在范围内,而是问题是您分配给inside if语句的变量在范围[。它恰好与if语句外的变量具有相同的名称。

解决方案是将if / else语句的结果分配给变量。这是您的代码,只需最少的更改:

price = "2.22" priceFloat = if price not in [""] do elem(Float.parse(price), 0) else nil end IO.inspect(priceFloat)

但是,它仍然不是很惯用。您可以利用以下事实:当输入为空字符串时,Float.parse/1返回:error可以像使用case表达式那样将其写入:

priceFloat = case Float.parse(price) do {float, ""} -> float :error -> nil end


1
投票
您可以结合使用模式匹配和方法重载来解决问题:

defmodule Example do def parsePrice(""), do: nil def parsePrice(price) when is_float(price), do: price def parsePrice(price) when is_binary(price) do {float, _} = Float.parse(price) float end end Example.parsePrice(2.22) |> IO.inspect Example.parsePrice("2.22") |> IO.inspect

((使用case语句可以实现等效项)

如果将非二进制(字符串)或浮点数的任何内容传递给此函数,将导致模式不匹配的错误。如果您有一些错误报告,这可能会很好,这样您就可以检测到代码的意外使用。

为了获得更好的调试体验,建议您通过IEx.pry/0使用内置调试器。


0
投票
出于多样性的考虑,我将发布另一种使用IEx.pry/0特殊形式的方法。

with/1

这里我们仅明确匹配浮点数。任何尾随的垃圾将被丢弃。如果匹配成功,则返回浮点数,否则,返回with {f, ""} <- Float.parse("3.14"),
  do: f,
  else: (_ -> nil)


[小心nil可能被看起来像科学记数法的垃圾所混淆。

Float.parse/1

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