与 nil 比较 returns true
Comparison with nil returns true
似乎以下表达式的计算结果为 "true"
:
if nil["nonexistent"] > 0.7 do "true" else "false" end
防止此类错误的惯用方法是什么?就我而言,我有一张地图,可能是也可能不是 nil
。
有很多方法可以做到这一点,我认为没有一种是特别“惯用”的方法。在大多数情况下,我会使用守卫或模式匹配来简单地确保映射的类型或键的值。
if is_float(mymap?["maybe_existent"]) do
mymap?["maybe_existent"] > 0.7
else
false
end
或
if is_map(mymap?) do
mymap?["nonexistent"] > 0.7
else
false
end
或
case mymap? do
%{"maybeexistent" => existent} when is_number(existent) ->
existent > 0.7
_ ->
false
end
或
with %{"existent" => existent} when is_number(existent) <- mymap? do
existent > 0.7
else
_ -> false
end
或
def f(%{"existent" => existent), do: existent > 0.7
def f(_), do: false
我认为一般情况下,当多个中间处理步骤混入一个函数时,就会出现这种问题。您通常希望分解逻辑以在较小进程的管道中对数据进行操作(我说的是抽象的“管道”,不一定是使用 |>
宏形成的 Elixir 管道),并且有将一些逻辑分解成漂亮的私有辅助函数当然没有错。
因此,例如,您可能有一个数据列表,这些数据可能是也可能不是地图(也许它们可能是 nils,或者完全是其他东西)。您应该将该问题拆分到流程管道的一个单独部分,以便在检查密钥值时,您已经确切知道您正在操作的值:
things = [%{a: 1}, nil, %{a: 3}, nil, nil, %{a: 0}]
things
|> Stream.filter(&is_map/1)
|> Stream.filter(& is_number(&1.a))
|> Stream.filter(& &1.a > 0.7)
|> Enum.to_list()
# results in: [%{a: 1}, %{a: 3}]
这是一种动态类型的语言,因此您可以自行决定在检查可能的不匹配类型或缺失数据时要多谨慎。在前面的示例中,键 :a
可能不存在于映射中,我们没有检查它,而是选择假设它存在,如果我们已经知道我们正在处理地图。也许你应该在这里提供更严格的检查。由你决定。您可以通过使用另一个过滤器,或者使用 well-defined 结构而不是映射来做到这一点。
或者您可能根本不是从一组数据开始的,而是您只是收到了一个数据点(可能来自外部数据点),您需要检查其中一个键的值,然后你可以通过一系列定义的函数来转换它:
def handle_in(:create_thing, %{"thing" => mymap?}, socket) do
if thing_worthy?(mymap?) do
thing = make_thing(mymap?)
{:reply, {:ok, %{thing: thing}}, socket}
else
{:reply, {:error, :create_thing_fail}, socket}
end
end
defp thing_worthy?(mymap) do
mymap
|> my_guarantee_key("existent")
|> my_exceeds_threshold?(0.7)
end
但除此之外,我可能只使用 case
或 if
语句进行一些保护检查,类似于上面的第一个示例。
我想提供一个替代解决方案:使用 Map.get
而不是 []
。虽然 []
可以索引 nil
返回 nil
,但 Map.get
(和其他 Map
函数)在这些情况下会崩溃,让您可以检测到错误:
iex(1)> Map.get(nil, "key")
** (BadMapError) expected a map, got: nil
(elixir 1.10.3) lib/map.ex:450: Map.get(nil, "key", nil)
iex(1)> nil["key"]
nil
然后,如果崩溃不是你想要的,你可以使用 ||
来确保第一个参数是一个映射并提供一些默认值:
iex(2)> x = nil
iex(3)> Map.get(x || %{}, "key", 0) > 7
false
似乎以下表达式的计算结果为 "true"
:
if nil["nonexistent"] > 0.7 do "true" else "false" end
防止此类错误的惯用方法是什么?就我而言,我有一张地图,可能是也可能不是 nil
。
有很多方法可以做到这一点,我认为没有一种是特别“惯用”的方法。在大多数情况下,我会使用守卫或模式匹配来简单地确保映射的类型或键的值。
if is_float(mymap?["maybe_existent"]) do
mymap?["maybe_existent"] > 0.7
else
false
end
或
if is_map(mymap?) do
mymap?["nonexistent"] > 0.7
else
false
end
或
case mymap? do
%{"maybeexistent" => existent} when is_number(existent) ->
existent > 0.7
_ ->
false
end
或
with %{"existent" => existent} when is_number(existent) <- mymap? do
existent > 0.7
else
_ -> false
end
或
def f(%{"existent" => existent), do: existent > 0.7
def f(_), do: false
我认为一般情况下,当多个中间处理步骤混入一个函数时,就会出现这种问题。您通常希望分解逻辑以在较小进程的管道中对数据进行操作(我说的是抽象的“管道”,不一定是使用 |>
宏形成的 Elixir 管道),并且有将一些逻辑分解成漂亮的私有辅助函数当然没有错。
因此,例如,您可能有一个数据列表,这些数据可能是也可能不是地图(也许它们可能是 nils,或者完全是其他东西)。您应该将该问题拆分到流程管道的一个单独部分,以便在检查密钥值时,您已经确切知道您正在操作的值:
things = [%{a: 1}, nil, %{a: 3}, nil, nil, %{a: 0}]
things
|> Stream.filter(&is_map/1)
|> Stream.filter(& is_number(&1.a))
|> Stream.filter(& &1.a > 0.7)
|> Enum.to_list()
# results in: [%{a: 1}, %{a: 3}]
这是一种动态类型的语言,因此您可以自行决定在检查可能的不匹配类型或缺失数据时要多谨慎。在前面的示例中,键 :a
可能不存在于映射中,我们没有检查它,而是选择假设它存在,如果我们已经知道我们正在处理地图。也许你应该在这里提供更严格的检查。由你决定。您可以通过使用另一个过滤器,或者使用 well-defined 结构而不是映射来做到这一点。
或者您可能根本不是从一组数据开始的,而是您只是收到了一个数据点(可能来自外部数据点),您需要检查其中一个键的值,然后你可以通过一系列定义的函数来转换它:
def handle_in(:create_thing, %{"thing" => mymap?}, socket) do
if thing_worthy?(mymap?) do
thing = make_thing(mymap?)
{:reply, {:ok, %{thing: thing}}, socket}
else
{:reply, {:error, :create_thing_fail}, socket}
end
end
defp thing_worthy?(mymap) do
mymap
|> my_guarantee_key("existent")
|> my_exceeds_threshold?(0.7)
end
但除此之外,我可能只使用 case
或 if
语句进行一些保护检查,类似于上面的第一个示例。
我想提供一个替代解决方案:使用 Map.get
而不是 []
。虽然 []
可以索引 nil
返回 nil
,但 Map.get
(和其他 Map
函数)在这些情况下会崩溃,让您可以检测到错误:
iex(1)> Map.get(nil, "key")
** (BadMapError) expected a map, got: nil
(elixir 1.10.3) lib/map.ex:450: Map.get(nil, "key", nil)
iex(1)> nil["key"]
nil
然后,如果崩溃不是你想要的,你可以使用 ||
来确保第一个参数是一个映射并提供一些默认值:
iex(2)> x = nil
iex(3)> Map.get(x || %{}, "key", 0) > 7
false