在“编程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传递给该函数的第一个参数是atom :get
。这有什么用?
Elixir传递给函数的第三个参数是绑定到的函数next_fn
。它在文档中的哪里说明该函数需要多少个参数?该功能有什么作用?我们应该如何使用next_fn
?在我看来,该for
构造已经在列表中的每个地图上进行了迭代,因此名称next_fn
甚至意味着什么?被next_fn
用来以某种方式标记进一步审议的行?
结果列表中的零是哪里来的?
而且,我要说的是:该示例是我在任何编程书籍中都看到过的最糟糕的示例之一,因为没有足够的讨论该示例,而且文档get_in()
很烂。这意味着至少有三个人不了解get_in()
:我,戴夫·托马斯(Dave Thomas)和编写文档的人-因为如果您无法解释某些内容,他们自己就不会理解。
编辑:我在源代码中找到了这一点:
def get_in(data, [h | t]) when is_function(h),
do: h.(:get, data, &get_in(&1, t))
什么是&1
参考呢?data
?为什么不只是使用data
呢?
好吧,我已经在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
关键row
,如果row.language
包含“R”。
最后,以下代码片段显示了nil
来源:
iex(5)> for x <- [1, 2, 3] do
...(5)> if x == 1_000_000, do: x+1
...(5)> end
[nil, nil, nil]
像Ruby中一样,do block
Elixir中的a似乎返回了最后一个被求值的表达式的值。而且,当ado block
不评估表达式时,默认情况下会do block
返回nil
。因此,如果ifrow.language
不包含“ r”,则将跳过if语句,并且ifdo block
不评估任何表达式,因此默认情况下do block
返回nil。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句