在“ Programming Elixir 1.6”中,有以下示例:
authors = [
%{name: "José", language: "Elixir"},
%{name: "Matz", language: "Ruby"},
%{name: "Larry", language: "Perl"}
]
languages_with_an_r = fn (:get, collection, next_fn) ->
for row <- collection do
if String.contains?(row.language, "r") do
next_fn.(row)
end
end
end
IO.inspect get_in(authors, [languages_with_an_r, :name])
#=> ["José", nil, "Larry"]
我对示例有一些疑问:
您传递给get_in()
的函数由Elixir调用,并且Elixir传递给该函数的第一个参数是原子:get
。这有什么用?
Elixir传递给函数的第三个参数是绑定到next_fn
的函数。它在文档中的哪里说明该函数需要多少个参数?该功能有什么作用?我们应该如何使用next_fn
?在我看来,for
构造已经在列表中的每个映射上进行了迭代,因此名称next_fn
甚至意味着什么?是否使用next_fn
标记行以作进一步考虑?
结果列表中的零是哪里来的?
而且,我要说的是:该示例是我在任何编程书籍中都看到过的最糟糕的示例之一,因为对该示例的讨论不够,并且get_in()
的文档很烂。这意味着至少有三个人不了解get_in()
:我,戴夫·托马斯(Dave Thomas)和编写文档的人-因为如果您无法解释某些内容,那么他们自己就不会理解。 / p>
编辑:我在source code中找到了这个
:def get_in(data, [h | t]) when is_function(h),
do: h.(:get, data, &get_in(&1, t))
&1
指的是什么? data
?那么为什么不只使用data
呢?
答案 0 :(得分:1)
好吧,我在iex中玩了一段时间:
iex(13)> mymax = fn x -> &max(&1, x) end
#Function<6.99386804/1 in :erl_eval.expr/5>
iex(15)> max_versus_3 = mymax.(3)
#Function<6.99386804/1 in :erl_eval.expr/5>
iex(16)> max_versus_3.(4)
4
iex(17)> max_versus_3.(2)
3
看起来语法&max(&1, 3)
返回了匿名函数:
fn (arg) -> max(&1, 3)
,当周围的范围内x = 3时,语法&max(&1, x)
也会返回该函数:
fn (arg) -> max(&1, 3)
和&1
将成为调用匿名函数的任何单个arg。
在此示例中:
authors = [
%{name: "José", language: "Elixir"},
%{name: "Matz", language: "Ruby"},
%{name: "Larry", language: "Perl"}
]
languages_with_an_r = fn (:get, collection, next_fn) ->
for row <- collection do
if String.contains?(row.language, "r") do
next_fn.(row)
end
end
end
IO.inspect get_in(authors, [languages_with_an_r, :name])
#=> ["José", nil, "Larry"]
在这里致电get_in()
:
IO.inspect get_in(authors, [languages_with_an_r, :name])
与源代码中的以下函数定义匹配:
def get_in(data, [h | t]) when is_function(h),
do: h.(:get, data, &get_in(&1, t))
这将创建以下绑定:
data = authors
h = languages_with_an_r
t = [:name]`
然后Elixir执行该函数的主体并调用:
h.(:get, data, &get_in(&1, t))
等效于:
languages_with_an_r.(
:get,
authors,
fn (arg) -> get_in(&1, [:name])
这将创建绑定:
next_fn = fn (arg) -> get_in(&1, [:name])
因此,在作者示例中,该行:
next_fn.(row)
等同于调用:
fn (row) -> get_in(&1, [:name])
这会使get_in()
使用以下参数执行:
get_in(row, [:name])
,对get_in()
的调用将返回与:name
中的row
键对应的值。我认为,如果将languages_with_an_r()
定义中的参数变量重命名,则作者的示例会更清楚:
languages_with_an_r = fn (:get, collection, search_for_next_key_in) ->
for row <- collection do
if String.contains?(row.language, "r") do
search_for_next_key_in.(row)
end
end
end
如果:name
包含“ r”,则该代码仅在row
中搜索row.language
键。
最后,以下代码片段显示了nil
的来源:
iex(5)> for x <- [1, 2, 3] do
...(5)> if x == 1_000_000, do: x+1
...(5)> end
[nil, nil, nil]
就像Ruby中一样,Elixir中的do block
似乎返回了最后一个被求值的表达式的值。而且,当do block
不对表达式求值时,默认情况下do block
返回nil
。因此,如果row.language
不包含“ r”,则将跳过if语句,并且do block
不计算任何表达式,因此默认情况下do block
返回nil。 / p>