3

我正在用 Elixir 编写游戏引擎。(是的,我知道这不是一种天生适合的语言——重点是看看非典型语言的使用如何影响结果的结构。)

因此,我在游戏开始时要运行几个监督者——但他们应该监督的具体内容取决于游戏。我的想法是让用户在config.exs文件中以元组列表的形式列出必要的子项,以及参数和选项,然后主管本身将简单地从应用程序环境中提取这些元组并将它们的内容用作worker\2(或worker\3,视情况而定)。

但是,我找不到任何与 Python 的元组解包等效的 Elixir。对于这种特定情况,我可以通过一个简单的函数自己完成:

def unpack_worker({module, args}) do
  worker(module, args)
end

def unpack_worker({module, args, opts}) do
  worker(module, args, opts)
end

但这充其量感觉很笨拙,并且必须为我可能需要这种可配置性的每个功能重新编写。

4

3 回答 3

8

我相信您正在寻找Tuple.to_list/1apply/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
于 2017-02-27T04:56:11.000 回答
1

我认为您需要知道元组的大小才能正确访问元素。也许对您的用例更好的数据结构是关键字列表,特别是考虑到它是您从配置中获得的?然后你可以解压 worker:, args: 并将剩余部分留作选项?

于 2017-02-26T23:51:02.073 回答
0

我相信你会想要一个elem/2tuple_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///多功能头或其他东西来区分您正在尝试做的事情casecond

于 2017-02-26T23:51:35.710 回答