为什么我的 Elixir 函数返回一个列表列表?

Why is my Elixir function returning a list of lists?

我有一个由函数 make_struct 编辑的结构 return 完全像这样:

%Example.Struct{example: 1, example_again: 2}

(即不带括号,如:[ %Example... ]),至少我认为它像上面那样 return,但是函数在 GenServer 模块中,有时我注意到我的函数 return出于某种我不理解的原因在列表中输入一个值?

我想要return这些结构的列表:

def foo(data_as_a_list) do
   my_list = []
   for entry <- data_as_a_list do
     my_list = [ make_struct(entry) | my_list ]
   end
end

这是return结构列表,每个结构都在列表中:

[
  [ 
    %Example.Struct{example: 1, example_again: 2} 
  ],
  [ 
    %Example.Struct{example: 1, example_again: 2} 
  ]
]

我只想:

[
   %Example.Struct{example: 1, example_again: 2},
   %Example.Struct{example: 1, example_again: 2}
]

Elixir 的 for 不像大多数语言的 for 循环那样工作 - 它们是理解,而不是循环。我建议阅读 the Elixir guide's page on it.

理解已经return一个列表(默认情况下;当指定:into时可能是另一个Collectable),其中包含return的每次执行12=] 的 do 块。它在简单情况下就像 Enum.map 一样。所以你可以使用其中任何一个来获得你想要的结果:

def foo(data_as_a_list) do
  for entry <- data_as_a_list do
    make_struct(entry)
  end
end
def foo(data_as_a_list) do
  Enum.map(data_as_a_list, &make_struct/1)
end

我认为第二个更加地道,因为 mapping 函数非常常见。理解主要用于当您有更复杂的需求时。

您的代码中有几点需要指出。

  1. 您正在做的是分配 my_list = [] 然后使用 for 更新 my_list 的想法是错误的。

这在语法上并没有错,这就解释了为什么您没有收到错误消息,而是把事情搞混了。

Elixir 中的东西是不可变的。这意味着在您的 for 中,您并不是真正地更新 my_list,而是在每个“迭代”上定义新的 my_list,这些迭代的范围是 for 构造并且什么都没有处理它之外的事情。

当你运行像a = 2iex你得到回来2,因为“赋值”returns赋值。或者因为结果是最后计算的结果,即 2.

考虑到这一点,您的代码相当于:

def foo(data_as_a_list) do
   my_list = []
   for entry <- data_as_a_list do
     [ make_struct(entry) | my_list ]
   end
end

Notice, however, that because things are immutable, every time [ make_struct(entry) | my_list ] is read, my_list equals []. Both in the updated and in your original code.

  1. for in 不是迭代器构造,而是列表推导式构造。

在 Elixir 中,for 不只是循环遍历事物,而是生成一个列表,其中包含对事物的操作结果。最简单的示例是:for i <- 1..5, do: i 生成 [1, 2, 3, 4, 5],尽管事先没有正式的列表或在 for 构造中更新列表。

考虑到这两点,如果您想要的是在 data_as_a_list 的每个项目上获得一个调用 make_struct 的列表,您可以使用 for 实现它与:

def foo(data_as_a_list) do
   for entry <- data_as_a_list do
     make_struct(entry)
   end
end