我可以像 Elixir 中其他语言的闭包一样捕获块外的变量吗?
Can I capture variable outside of block like closure of other language in Elixir?
defmodule Test do
use Retry
import Stream
def call_service(count) do
IO.puts "call_service #{count}"
%{"errors" => true}
end
def hello do
count = 0
retry_while with: linear_backoff(500, 1) |> take(5) do
count = count + 1 # incorrect !!!
call_service(count)
|> case do
result = %{"errors" => true} -> {:cont, result}
result -> {:halt, result}
end
end
end
end
以上示例引用自重试模块的document。
我想在这里做的是知道 call_service 函数中的计数值。您可能已经注意到,该示例没有按我的预期运行。
我可以让计数值表示函数在 call_service 函数中被调用了多少次吗?
不,你不能在“[its] 块之外”赋值一个变量——这就是你听到“在 Elixir 中,一切都是赋值”的部分含义。
的常见模式
# pseudo-code
x = 0
for y in z {
# do something
x = x + 1
}
在 Elixir 中不起作用。相反,您经常需要依赖 map 和 reduce 函数(通常由 Enum 模块提供)。
考虑这个依赖 Enum
重复调用函数的简单模块。这里我们使用保护子句来限制我们实际进行的调用次数,即使我们在更大范围内枚举。
defmodule Foo do
def repeat do
Enum.each(1..10, fn n ->
call_service(n)
end)
end
defp call_service(count) when count > 7 do
IO.puts("Whoops... called too many times!")
{:error, "Called too many times"}
end
defp call_service(count) do
IO.puts("Count is #{count}")
{:ok, "Called the service!"}
end
end
如果我们通过执行 Foo.repeat()
来 运行 这段代码,我们会看到如下输出:
Count is 1
Count is 2
Count is 3
Count is 4
Count is 5
Count is 6
Count is 7
Whoops... called too many times!
Whoops... called too many times!
Whoops... called too many times!
这表明我们枚举了整个数字范围 (1-10),但当计数大于 7 时我们执行了一些不同的操作。
更常见的是,当您想在“循环”过程中重新分配一个数字时,您最终会使用 Enum.map/2
或 Enum.reduce/3
。
查看重试后,我认为 retry_while
无法达到您想要的结果。但是,您可以将 DelayStreams 与一个简单的 Enum.reduce_while/2
一起使用,它可以跟踪计数,如下例所示。
defmodule World do
def call_service(count, limit) do
IO.inspect(count, label: "count")
cond do
limit == 7 -> %{errors: true}
count == limit -> %{errors: false}
true -> %{errors: true}
end
end
def hello(limit) do
50
|> Retry.DelayStreams.linear_backoff(1)
|> Enum.take(limit * 2)
|> Enum.reduce_while(0, fn delay, count ->
Process.sleep(delay)
case call_service(count, limit) do
%{errors: false} = success -> {:halt, {:ok, success}}
error when count == limit -> {:halt, {:error, error}}
_ -> {:cont, count + 1}
end
end)
end
end
结果如下:
iex(9)> World.hello 3
count: 0
count: 1
count: 2
count: 3
{:ok, %{errors: false}}
iex(10)> World.hello 7
count: 0
count: 1
count: 2
count: 3
count: 4
count: 5
count: 6
count: 7
{:error, %{errors: true}}
iex(11)>
defmodule Test do
use Retry
import Stream
def call_service(count) do
IO.puts "call_service #{count}"
%{"errors" => true}
end
def hello do
count = 0
retry_while with: linear_backoff(500, 1) |> take(5) do
count = count + 1 # incorrect !!!
call_service(count)
|> case do
result = %{"errors" => true} -> {:cont, result}
result -> {:halt, result}
end
end
end
end
以上示例引用自重试模块的document。
我想在这里做的是知道 call_service 函数中的计数值。您可能已经注意到,该示例没有按我的预期运行。
我可以让计数值表示函数在 call_service 函数中被调用了多少次吗?
不,你不能在“[its] 块之外”赋值一个变量——这就是你听到“在 Elixir 中,一切都是赋值”的部分含义。
的常见模式# pseudo-code
x = 0
for y in z {
# do something
x = x + 1
}
在 Elixir 中不起作用。相反,您经常需要依赖 map 和 reduce 函数(通常由 Enum 模块提供)。
考虑这个依赖 Enum
重复调用函数的简单模块。这里我们使用保护子句来限制我们实际进行的调用次数,即使我们在更大范围内枚举。
defmodule Foo do
def repeat do
Enum.each(1..10, fn n ->
call_service(n)
end)
end
defp call_service(count) when count > 7 do
IO.puts("Whoops... called too many times!")
{:error, "Called too many times"}
end
defp call_service(count) do
IO.puts("Count is #{count}")
{:ok, "Called the service!"}
end
end
如果我们通过执行 Foo.repeat()
来 运行 这段代码,我们会看到如下输出:
Count is 1
Count is 2
Count is 3
Count is 4
Count is 5
Count is 6
Count is 7
Whoops... called too many times!
Whoops... called too many times!
Whoops... called too many times!
这表明我们枚举了整个数字范围 (1-10),但当计数大于 7 时我们执行了一些不同的操作。
更常见的是,当您想在“循环”过程中重新分配一个数字时,您最终会使用 Enum.map/2
或 Enum.reduce/3
。
查看重试后,我认为 retry_while
无法达到您想要的结果。但是,您可以将 DelayStreams 与一个简单的 Enum.reduce_while/2
一起使用,它可以跟踪计数,如下例所示。
defmodule World do
def call_service(count, limit) do
IO.inspect(count, label: "count")
cond do
limit == 7 -> %{errors: true}
count == limit -> %{errors: false}
true -> %{errors: true}
end
end
def hello(limit) do
50
|> Retry.DelayStreams.linear_backoff(1)
|> Enum.take(limit * 2)
|> Enum.reduce_while(0, fn delay, count ->
Process.sleep(delay)
case call_service(count, limit) do
%{errors: false} = success -> {:halt, {:ok, success}}
error when count == limit -> {:halt, {:error, error}}
_ -> {:cont, count + 1}
end
end)
end
end
结果如下:
iex(9)> World.hello 3
count: 0
count: 1
count: 2
count: 3
{:ok, %{errors: false}}
iex(10)> World.hello 7
count: 0
count: 1
count: 2
count: 3
count: 4
count: 5
count: 6
count: 7
{:error, %{errors: true}}
iex(11)>