为什么 Julia 闭包不复制数组?



刚刚在我的程序中发现了一个令人讨厌的错误,基于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块是局部的,在全局范围内不存在。f仍然可以访问它,即使它在技术上已经超出了范围。这就是闭包的意思。

由于l超出了范围,它不再可访问,除非通过闭包f闭包,可以将其作为闭合变量访问。


附言。我将在这里冒昧地假设你期待的是类似matlab的行为。与 matlab 的最大区别在于,当您在那里定义匿名函数句柄时,它会通过复制所有变量并使它们成为函数"对象"的一部分来捕获工作区的当前状态。您可以使用functions命令确认这一点。Matlab没有与julia相同的引用。这是 julia 的优势,而不是弱点,因为它允许用户利用避免重新分配内存的优化,这在 matlab* 中更难实现。

* 虽然公平地说,MATLAB 在其他方面大放异彩,试图为您优化这一点


编辑:Liso指出了评论中一个非常重要的陷阱。假设全局工作区中已经存在l,我们键入

let l=l

虽然这是完全有效的语法,使l成为let块的局部变量,但这仍然被简单地初始化为对全局l引用。因此,对全局l的任何更改仍将影响关闭,这不是您想要的。在这种情况下,您应该尝试通过制作副本(或深度副本,具体取决于您的用例)来"模仿"matlab 行为,这样局部变量一旦超出范围并变得"封闭",即

let l = deepcopy(l)

此外,为了完整起见,当一个人在 julia 中进行闭包时,值得指出这是如何在后台实现的:你生成的f函数只是一个可调用的对象,包含它需要注意的每个"封闭"变量的字段;你甚至可以将其作为f.l访问。

最新更新