我正在使用Ivo Balbaert's book学习Julia。他使用以下示例:
anon = Array{Any}(undef, 2)
for i = 1:2
anon[i] = () -> println(i)
i += 1
end
现在调用此数组输出中的两个函数:
julia> anon[1](); anon[2]()
2
3
我不明白为什么输出是2、3而不是1、2。在第一次通过循环i = 1
时,使anon[1] = () -> println(1)
如此。作者继续:
在这里,
anon[1]
和anon[2]
都是匿名函数。当他们是 用anon[1]()
和anon[2]()
调用,它们打印2
和3
( 我创建它们时加上一个。
然后使用let
实现预期的行为。但是,我在此解释中缺少的是Julia范围规则如何操作才能产生2(3)的第一个(意外的)结果。换句话说,值2和3是如何变成的?有人可以解释一下吗?谢谢!
答案 0 :(得分:2)
这非常棘手。您需要知道两件事:
for
循环变量i
中,每次迭代都会获得新的绑定(我想您知道吗-我不知道Ivo的书,但是从您的问题中我想这就是他正在讨论的内容在其中)现在要解释第二点,请看以下内容(我假设您已经运行了上面的代码):
julia> anon[1].i
Core.Box(2)
julia> anon[1].i.contents
2
您会看到anon[1]
已将循环的第一次迭代中存在的对i
的绑定装箱。就像在第二个循环中一样,i
的绑定是新鲜的anon[2]
对此新鲜绑定的引用。
您甚至可以像这样访问此存储位置:
julia> anon[1].i.contents = 100
100
julia> anon[1]()
100
甚至是这样(不推荐):
julia> for i = 1:2
anon[i] = () -> println(i)
anon[i].i.contents = 100 + i
i += 1
println(i)
end
102
103
julia> anon[1]()
102
julia> anon[2]()
103
最后请注意,在循环的一次迭代中,分配给变量i
不会更改绑定(您正在写入相同的内存位置)。