@patrick-oscity 给出了一个非常深入的答案,我非常喜欢它。但是,我已经使用了一个版本,它可以通过对 pin 运算符使用模式匹配来做到这一点。
对于上下文,我正在编写一个累加器,当所有输入都已收到时,它会将其所有输入的结果转发给执行器。我还希望作为列表的累积输出遵守最初发送其输出的进程的预定义顺序。
完成此操作后,累加器再次开始等待消息。
累加器如下所示:
def start_link(actuator, actuator_pid) do
Task.start_link(fn -> loop(actuator, actuator_pid, actuator.inputs, []) end)
end
defp loop(actuator, actuator_pid, [], acc) do
result = acc |> Enum.reverse
send actuator_pid, {:forward, self(), result}
loop(actuator, actuator_pid, actuator.inputs, [])
end
defp loop(actuator, actuator_pid, [input | remaining_inputs], acc) do
receive do
{:forward, ^input, output} ->
loop(actuator, actuator_pid, remaining_inputs, [output | acc])
end
end
为了证明它符合我的要求,对此的测试如下:
test "When I recieve the outputs from all my inputs, then I return the accumulated result in the order of my actuator's inputs" do
{_, pid0} = Task.start_link(fn -> test_loop end)
{_, pid1} = Task.start_link(fn -> test_loop end)
{_, pid2} = Task.start_link(fn -> test_loop end)
actuator = %Cerebrum.Actuator{
inputs: [pid0, pid1, pid2]
}
actuator_pid = self()
{_, pid} = start_link(actuator, actuator_pid)
send pid, {:forward, pid0, 0}
refute_receive {:forward, pid, [0]}
send pid, {:forward, pid1, 1}
refute_receive {:forward, pid, [0, 1]}
send pid, {:forward, pid2, 2}
assert_receive {:forward, pid, [0, 1, 2]}
send pid, {:forward, pid0, 0}
send pid, {:forward, pid1, 1}
send pid, {:forward, pid2, 2}
assert_receive {:forward, pid, [0, 1, 2]}
send pid, {:forward, pid0, 0}
send pid, {:forward, pid2, 2}
send pid, {:forward, pid1, 1}
assert_receive {:forward, pid, [0, 1, 2]}
send pid, {:forward, pid1, 1}
send pid, {:forward, pid0, 0}
send pid, {:forward, pid2, 2}
assert_receive {:forward, pid, [0, 1, 2]}
send pid, {:forward, pid1, 1}
send pid, {:forward, pid2, 2}
send pid, {:forward, pid0, 0}
assert_receive {:forward, pid, [0, 1, 2]}
send pid, {:forward, pid2, 2}
send pid, {:forward, pid1, 1}
send pid, {:forward, pid0, 0}
assert_receive {:forward, pid, [0, 1, 2]}
send pid, {:forward, pid2, 2}
send pid, {:forward, pid1, 1}
send pid, {:forward, pid0, 0}
assert_receive {:forward, pid, [0, 1, 2]}
end
defp test_loop do
test_loop
end