我在crash
中实施GenServer
函数来测试将管理此过程的主管和注册表的行为。工作在Elixir完成,但我相信它也可能涉及Erlang。
我可以调用raise()
,但首先我实施了1/0
作为崩溃的原因。对于以下代码,编译器是一个聪明人:
def handle_cast(:crash, state) do
a = 1 / 0
{:noreply, state}
end
我收到了警告:
warning: this expression will fail with ArithmeticError
lib/xyz/worker.ex:47
公平。毕竟,即使是旧的C或C ++编译器也能够检测到这种事情。我尝试用a = 1 / 0
替换a = 1 / :math.sin(0)
的库调用。同样的警告。我的好奇心醒了,我尝试了同样的结果。实际上,这似乎不容易欺骗编译器!最后,我说:
a = 1 / Enum.reduce([0, 1, -1], 0, fn(n, acc) -> n+acc end)
并得到了一个不同的警告:
warning: the result of the expression is ignored (suppress the warning by assigning the expression to the _ variable)
lib/xyz/worker.ex:50
第50行为a = 1 / Enum.reduce(...)
。
我花了几个小时尝试不同的事情,总是得到警告。
我相信第一个是因为编译器能够从常量参数和函数类型中预先计算结果并最终内联操作1 / 0
。
但我不理解第二次警告。在其中一个测试中,我写道:
def handle_cast(:crash, state) do
a = 1 / Enum.reduce([0, 1, -1], 0, fn(n, acc) -> n+acc end)
# {:noreply, state}
end
实际上会抑制警告,但我真的不明白为什么。
NB.1 :版本:
maurice@mickey> elixir -v
Erlang/OTP 20 [erts-9.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Elixir 1.6.1 (compiled with OTP 19)
NB.2 :我很清楚question,但我不认为这里的回复适用。
暂时,我会打电话给raise(...)
......
答案 0 :(得分:2)
警告实际上是告诉您该怎么做:将a = ...
替换为_ = ...
。
在您的示例中,您将操作的结果分配给名为a
的变量。编译通知您再也不会使用该变量,因此它会抱怨它。
_
。在执行_ = ...
或def my_function(_, second_paramter)
时,您基本上会告诉编译器:
我不想使用该值,所以请不要抱怨
要提供有关忽略值的更多信息,您还可以使用下划线(_
)为变量添加前缀,该变量具有相同的用途。在您的情况下,可能是_a = ...
。
这在忽略函数中的参数时非常有用,而不会让读者猜测该参数的含义。因此def get(:thing, _)
可能会成为def get(:thing, _opts)
。
然后你问为什么注释掉的版本没有产生这个错误。答案就在于函数的返回值等于该函数的最后一个语句。
所以这个功能
def my_function do
1
2
3
end
返回3,而此函数
def my_function do
:a
:b
end
返回:b
。在你的例子中如此
def handle_cast(:crash, state) do
a = 1 / Enum.reduce([0, 1, -1], 0, fn(n, acc) -> n+acc end)
# {:noreply, state}
end
您注释掉了# {:noreply, state}
元组,a = ...
语句成为函数中的最后一个。从现在开始创建变量a
并将其作为" return"的一部分进行评估,编译器停止抱怨。
另一方面,可以证明在函数的最后一行中的变量赋值是无用的。因此,这可能实际上保证了GitHub上的低优先级问题。
答案 1 :(得分:0)
愚弄编译器直到最后,重新分配state
变量:
def handle_cast(:crash, state) do
state = Enum.reduce([0, 1, -1], 0, fn(n, acc) ->
n + acc
end)
{:noreply, state}
end
这样编译器会认为state
赋值是必要的(因为它被用作返回值。)