我正在GenServer
中实现一个crash
函数,以测试将管理此过程的主管和注册表的行为。工作是在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
这实际上抑制了警告,但我真的不明白为什么。
注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)
注2:我知道这个问题,但我认为答案不适用于这里。
暂时,我会打电话给raise(...)
...
简短版本
警告实际上是在告诉您该怎么做:将a = ...
替换为_ = ...
。
长版本
在手头的示例中,您将操作的结果分配给名为a
的变量。编译注意到你再也不会使用该变量,所以它会抱怨它。
Elixir知道这种情况的"特殊"变量称为_
。在执行_ = ...
或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
并将其作为"返回"的一部分进行评估,编译器停止抱怨。
另一方面,可以公平地证明函数最后一行中的变量赋值是无用的。因此,这实际上可能需要在 GitHub 上出现低优先级问题。
愚弄编译器直到最后,重新分配state
变量:
def handle_cast(:crash, state) do
state = Enum.reduce([0, 1, -1], 0, fn(n, acc) ->
n + acc
end)
{:noreply, state}
end
这样编译器就会认为state
赋值是必要的(因为它被用作返回值(。