(k, a, b, a1, b1) = (BigInt(2), BigInt(4), BigInt(1), BigInt(12), BigInt(4))
while k <= BigInt(4)
(p, q, k) = (k*k, BigInt(2)*k+BigInt(1), k+BigInt(1))
end
此代码可在Julia 0.6中编译并运行,但在1.0中会生成ERROR: UndefVarError: k not defined
。
两个版本之间是否有所更改? Julia 1.0中的这段代码有什么问题?
答案 0 :(得分:4)
shadowtalker的回答是正确的。但是,此代码存在一个重要问题,值得增加一些解释(并且注释太长了)。
在此情况下,Julia中的相关范围规则如下(如果您想阅读详细信息,可以在https://docs.julialang.org/en/latest/manual/variables-and-scoping/#Local-Scope-1处找到它们):
while
块引入了新的本地范围; global
关键字限定); local
关键字限定。现在-为什么这很重要?原因是,如果在全局范围内(例如,在Julia REPL中)运行代码,则代码的行为会有所不同;而在局部范围(例如,在函数内部)中运行时,代码的行为将有所不同。
如果在全局范围内运行它,则需要显示shadowtalker。但是,如果您要在函数内部,您无需更改任何内容。例如,此功能将正常工作:
function f()
(k, a, b, a1, b1) = (BigInt(2), BigInt(4), BigInt(1), BigInt(12), BigInt(4))
while k <= BigInt(4)
(p, q, k) = (k*k, BigInt(2)*k+BigInt(1), k+BigInt(1))
end
end
也不会创建函数,例如在全局范围内使用let
块,代码将按预期运行:
let
k, a, b, a1, b1 = BigInt(2), BigInt(4), BigInt(1), BigInt(12), BigInt(4)
while k <= BigInt(4)
(p, q, k) = (k*k, BigInt(2)*k+BigInt(1), k+BigInt(1))
end
k, a, b, a1, b1
end
因为let
创建了一个本地范围(我在let
块的末尾添加了该语句,使其对所引入变量的值求值,以便您可以检查它们)。
这是从Julia 0.6和更早版本开始的重大更改,在Julia 0.6和朱莉亚之前,Julia在硬本地作用域和软本地作用域之间进行了区别(请参见https://docs.julialang.org/en/release-0.6/manual/variables-and-scoping/#scope-of-variables-1),但是这种区别消失了-所有本地作用域现在的行为都相同。这是一个重大的变化,实际上这意味着您可以期望,如果将其复制粘贴到全局范围内,则在某些本地范围(在大多数情况下为函数)中正确运行的代码将更改其行为。根据我的经验,如上所示,使用let
块是缓解此问题的最简单方法。
答案 1 :(得分:2)
是的,有些改变了。我认为这是怎么回事:
在循环内分配给p
,q
和k
实际上会在以下位置创建新的p
,q
和k
绑定一个新的本地范围。然后,由于右侧还使用了k
,因此Julia尝试使用 local k
并失败了。
为了获得预期的语义(对在顶层定义的现有p
,q
和k
进行突变),您需要首先将它们声明为“ global”:< / p>
while k <= BigInt(4)
global p, q, k
(p, q, k) = (k*k, BigInt(2)*k+BigInt(1), k+BigInt(1))
end
编辑:感谢Freenode上的用户AnAverageHuman弄清楚了这一点。