Julia的范围详细说明:在循环内定义闭包 [英] Julia scoping specifics: defining closure within loop

查看:85
本文介绍了Julia的范围详细说明:在循环内定义闭包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 Ivo Balbaert的书来学习Julia .他使用以下示例:

I am learning Julia using Ivo Balbaert's book. He uses the following example:

anon = Array{Any}(undef, 2)
for i = 1:2
    anon[i] = () -> println(i)
    i += 1
end

现在调用此数组输出中的两个函数:

Now calling the two functions in this array outputs:

julia> anon[1](); anon[2]()
2
3

我不明白为什么输出是2、3而不是1、2.在第一次通过循环i = 1时,使anon[1] = () -> println(1).作者继续:

I fail to understand why the output is 2, 3 instead of 1, 2. At the first pass through the loop i = 1, so that anon[1] = () -> println(1). The author continues:

在这里,anon[1]anon[2]都是匿名函数.当他们是 用anon[1]()anon[2]()调用,它们打印23( 我在创建它们时加上一个).

Here, both anon[1] and anon[2] are anonymous functions. When they are called with anon[1]() and anon[2](), they print 2 and 3 (the values of i when they were created plus one).

然后通过使用let实现预期的行为.但是,我在此解释中缺少的是如何使用Julia范围规则来产生2(3)的第一个(意外)结果.换句话说,值2和3如何变成?有人可以解释一下吗?谢谢!

The expected behavior is then achieved by using let. What I am missing in this explanation, however, is how Julia scoping rules operate in order to produce the first (unexpected) result of 2, 3. In other words, how do the values 2 and 3 come to be? Could someone please explain this? Thanks!

推荐答案

这非常棘手.您需要了解两件事:

This is pretty tricky. You need to know two things:

  • for循环变量中的i在每次迭代中都获得新的绑定(我想您知道它-我不知道Ivo的书,但是从您的问题中我想这就是他在其中讨论的内容)
  • Julia闭包是通过创建一个对象来实现的,该对象从外部范围捕获变量,然后可以访问它
  • within a for loop variable i gets a fresh binding on every iteration (I guess you know it - I do not know Ivo's book, but from your question I guess this is what he is discussing in it)
  • in Julia closures are implemented via a creation of an object that captures a variable from an outer scope and then it can access it

现在要解释第二点,请看以下内容(我假设您已经运行了上面的代码):

Now to explain the second point have a look at the following (I assume you have run the code above):

julia> anon[1].i
Core.Box(2)

julia> anon[1].i.contents
2

您会看到anon[1]已将循环中第一次迭代中出现的对i的绑定装箱.就像在第二个循环中一样,与i的绑定是新鲜的anon[2]对此新鲜绑定的引用.

And you can see that anon[1] has boxed the binding to i that was present in the first iteration of the loop. As in the second loop the binding to i is fresh anon[2] has a reference to this fresh binding.

您甚至可以像这样访问此存储位置:

You can even access this memory location like this:

julia> anon[1].i.contents = 100
100

julia> anon[1]()
100

甚至是这样(不推荐):

or even like this (not recommended):

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不会更改绑定(您正在写入相同的内存位置).

Finally note that within a single iteration of the loop assigning to variable i does not change the binding (you are writing to the same memory location).

这篇关于Julia的范围详细说明:在循环内定义闭包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆