基于 Julia 在定义闭包时不复制数组这一事实,我刚刚在我的程序中发现了一个讨厌的错误。这使得连续编程变得困难。选择此设计的动机是什么?
对于将我的关闭状态与程序状态分离有什么建议吗?
举个例子
l = [2 1; 0 0];
f = x -> l[2,2];
那么 f(1) = 0 但如果你改变 l[2,2] = 1,那么 f(1) = 1。
最佳答案
您认为这是一个“关闭”的假设不成立。 l
此时在匿名函数的上下文中不是“封闭”变量。它只是对从“外部”作用域继承的变量的引用(因为它没有在匿名函数内部重新定义)。
这是一个真实闭包的例子:
f = let l=[2 1;0 0]
x -> l[2,2];
end
变量 l
现在是 let
block 的局部变量,而不是出现在全局范围内。 f
仍然可以访问它,即使它在技术上已经超出了范围。这就是闭包的意思。
由于 l
已经超出范围,它不再可以访问,除非通过 f
,这是一个闭包,可以将其作为封闭变量访问。
附言。我将在这里冒险并假设您所期望的是类似 matlab 的行为。与 matlab 的最大区别在于,当您在那里定义匿名函数句柄时,它会通过复制所有变量并使它们成为函数“对象”的一部分来捕获工作区的当前状态。您可以使用 functions
命令确认这一点。 Matlab 没有像 julia 一样的引用。这是 julia 的优点,而不是缺点,因为它允许用户使用优化来避免重新分配内存,而这在 matlab* 中更难实现。
* 虽然公平地说,matlab 在其他方面也很出色,通过尝试为您优化它
编辑: Liso 在评论中指出了一个非常重要的陷阱。假设 l
已经存在于全局工作空间中,我们输入
let l=l
虽然这是完全有效的语法,使 l
成为 let
block 的局部变量,但它仍然被简单地初始化为 reference全局 l
。因此,对全局 l
的任何更改仍将影响闭包,这不是您想要的。在这种情况下,您应该尝试通过制作复制(或深层复制,取决于您的用例)来“模仿”matlab 行为,这样局部变量就真正独立于其他任何东西一次它超出范围并变为“关闭”,即
let l = deepcopy(l)
此外,为了完整起见,当在 julia 中创建闭包时,值得指出它是如何在幕后实现的:生成的 f
函数只是一个可调用对象,包含一个字段它需要注意的每个“封闭”变量;您甚至可以通过 f.l
访问它。
https://stackoverflow.com/questions/46612475/