在 Elixir 中使用元组作为函数的参数
Use a tuple as arguments for a function in Elixir
我正在用 Elixir 编写游戏引擎。 (是的,我知道这不是一种天生适合这种情况的语言——重点是看看非典型语言的使用如何影响结果的结构。)
因此,我有几位监督员 运行 在游戏开始时担任 - 但他们具体应该监督什么取决于游戏。我的想法是让用户在 config.exs
文件中列出必要的子项,加上参数和选项作为元组列表,然后主管本身只需从应用程序环境中提取这些元组并使用它们内容作为 worker
(或 worker
,视情况而定)的参数。
但是,我找不到任何与 Python 的元组解包等效的 Elixir。对于这个特定的案例,我可以使用一个简单的函数自己完成:
def unpack_worker({module, args}) do
worker(module, args)
end
def unpack_worker({module, args, opts}) do
worker(module, args, opts)
end
但这充其量感觉很笨拙,并且必须为我可能需要这种可配置性的每个功能重新编写。
我认为您需要知道元组的大小才能正确访问元素。也许对您的用例来说更好的数据结构是关键字列表,尤其是考虑到它是您从配置中获得的?然后你可以解压 worker:, args: 并将其余部分保留为选项?
我相信您会想要 elem/2
and tuple_size/1
功能的组合。
iex(1)> a = {:foo, :bar, :baz}
{:foo, :bar, :baz}
iex(2)> tuple_size(a)
3
iex(3)> elem(a, 0)
:foo
iex(4)> elem(a, 5)
** (ArgumentError) argument error
:erlang.element(6, {:foo, :bar, :baz})
请注意,如果您在元组中不存在的索引处请求一个元素,则会出现参数错误。这意味着您仍然需要使用 if
/ case
/ cond
/ 多功能头或其他东西来区分您正在尝试做的事情。
我相信您正在寻找 Tuple.to_list/1
和 apply/3
:
通过这些,您可以根据元组的内容调用正确数量的函数:
def unpack_worker(args) do
apply(__MODULE__, :worker, Tuple.to_list(args))
end
如果您现在调用 unpack_worker({})
,它将调用 worker()
,unpack_worker({:foo})
将调用 worker(:foo)
,依此类推。
演示:
defmodule A do
def worker, do: IO.puts 0
def worker(_), do: IO.puts 1
def worker(_, _), do: IO.puts 2
def worker(_, _, _), do: IO.puts 3
def unpack_worker(tuple), do: apply(__MODULE__, :worker, Tuple.to_list(tuple))
end
A.unpack_worker({})
A.unpack_worker({:a})
A.unpack_worker({:a, :b})
A.unpack_worker({:a, :b, :c})
输出:
0
1
2
3
我正在用 Elixir 编写游戏引擎。 (是的,我知道这不是一种天生适合这种情况的语言——重点是看看非典型语言的使用如何影响结果的结构。)
因此,我有几位监督员 运行 在游戏开始时担任 - 但他们具体应该监督什么取决于游戏。我的想法是让用户在 config.exs
文件中列出必要的子项,加上参数和选项作为元组列表,然后主管本身只需从应用程序环境中提取这些元组并使用它们内容作为 worker
(或 worker
,视情况而定)的参数。
但是,我找不到任何与 Python 的元组解包等效的 Elixir。对于这个特定的案例,我可以使用一个简单的函数自己完成:
def unpack_worker({module, args}) do
worker(module, args)
end
def unpack_worker({module, args, opts}) do
worker(module, args, opts)
end
但这充其量感觉很笨拙,并且必须为我可能需要这种可配置性的每个功能重新编写。
我认为您需要知道元组的大小才能正确访问元素。也许对您的用例来说更好的数据结构是关键字列表,尤其是考虑到它是您从配置中获得的?然后你可以解压 worker:, args: 并将其余部分保留为选项?
我相信您会想要 elem/2
and tuple_size/1
功能的组合。
iex(1)> a = {:foo, :bar, :baz}
{:foo, :bar, :baz}
iex(2)> tuple_size(a)
3
iex(3)> elem(a, 0)
:foo
iex(4)> elem(a, 5)
** (ArgumentError) argument error
:erlang.element(6, {:foo, :bar, :baz})
请注意,如果您在元组中不存在的索引处请求一个元素,则会出现参数错误。这意味着您仍然需要使用 if
/ case
/ cond
/ 多功能头或其他东西来区分您正在尝试做的事情。
我相信您正在寻找 Tuple.to_list/1
和 apply/3
:
通过这些,您可以根据元组的内容调用正确数量的函数:
def unpack_worker(args) do
apply(__MODULE__, :worker, Tuple.to_list(args))
end
如果您现在调用 unpack_worker({})
,它将调用 worker()
,unpack_worker({:foo})
将调用 worker(:foo)
,依此类推。
演示:
defmodule A do
def worker, do: IO.puts 0
def worker(_), do: IO.puts 1
def worker(_, _), do: IO.puts 2
def worker(_, _, _), do: IO.puts 3
def unpack_worker(tuple), do: apply(__MODULE__, :worker, Tuple.to_list(tuple))
end
A.unpack_worker({})
A.unpack_worker({:a})
A.unpack_worker({:a, :b})
A.unpack_worker({:a, :b, :c})
输出:
0
1
2
3