Julia 在for eachrow循环中使用变量会导致错误

Julia 在for eachrow循环中使用变量会导致错误,julia,Julia,我试图理解为什么在循环中使用变量I会导致问题 文件main2.jl: struct MyStruct a::Int32 b::Int32 c::String end df = DataFrame( A=Int[], B=Int[] ) push!(df, [1, 10]) push!(df, [2, 20]) push!(df, [3, 30]) insertcols!(df, 3, :C => MyStruct.(Int32(0), Int32(0), "")

我试图理解为什么在循环中使用变量
I
会导致问题

文件main2.jl

struct MyStruct
    a::Int32
    b::Int32
    c::String
end

df = DataFrame( A=Int[], B=Int[] )
push!(df, [1, 10])
push!(df, [2, 20])
push!(df, [3, 30])

insertcols!(df, 3, :C => MyStruct.(Int32(0), Int32(0), ""))
insertcols!(df, 3, :D => Vector{MyStruct})

println(df)

i = 1
for r in eachrow(df)
    i = i + 1
end
我得到:

julia> include("main2.jl")
|     A |     B |                 D |                    C |
| Int64 | Int64 |          DataType |             MyStruct |
|-------|-------|-------------------|----------------------|
|     1 |    10 | Array{MyStruct,1} | MyStruct(0, 0, \"\") |
|     2 |    20 | Array{MyStruct,1} | MyStruct(0, 0, \"\") |
|     3 |    30 | Array{MyStruct,1} | MyStruct(0, 0, \"\") |
ERROR: LoadError: UndefVarError: i not defined
Stacktrace:
 [1] top-level scope at /usr/home/.../main2.jl:19
 [2] include at ./boot.jl:328 [inlined]
 [3] include_relative(::Module, ::String) at ./loading.jl:1094
 [4] include(::Module, ::String) at ./Base.jl:31
 [5] include(::String) at ./client.jl:431
 [6] top-level scope at REPL[3]:1
in expression starting at /usr/home/.../main2.jl:18

julia> 

问题是
i
存在于全局范围内,当您在全局范围内为
编写
循环时,它会创建自己的子范围。您可以通过将
for
循环更改为

i = 1
for r in eachrow(df)
    global i
    i = i + 1
end
但是,在函数体内部,您不需要这样做(只要
i
存在于函数体中)

这归结为这样一个事实:在Julia中,您通常不应该在全局范围内编写非平凡的代码。将代码放入函数中被认为是合适的形式。如果代码不在函数中,则不会对其进行编译,也不会获得使用Julia的任何性能好处。有关范围规则的更多信息,请参见:

关于这个问题以及人们希望发生什么,已经有很多讨论。讨论或多或少从这里开始:然后在这里提出了一个解决方案:然后在这里讨论了一个新的潜在解决方案:


看来目前还没有就如何改变巴哈维奥达成真正的共识,因此它很可能会保持原样。就其价值而言,我更喜欢当前的行为,并认为它有一些优势,尽管它常常让新来者感到惊讶

感谢修复了这个问题,我仍然想知道为什么Julia会这样做,为什么在这种情况下你不得不指定
I
是全局的。我想我现在明白了范围界定规则,我只是不明白这样做的好处。对于新手来说,这确实是非常令人惊讶的。与使用@eval修改模块中的变量相同,即使我已在该模块中显式导出该变量。因此,我最终开始将所有内容放入函数中。只需将整个主代码移到函数main()中,然后在最后调用main()即可解决此问题。这种范围界定规则真的令人费解,到目前为止,我在朱莉娅身上看到的情况更糟(我想它们存在是有原因的,但它们一点也不直观)。下面是一篇文章,Stefan解释了这种行为背后的理据:我明白了,这澄清了范围界定为什么会这样工作。感谢
let
block提示。。我同意这种情况更好(虽然写一个主函数没什么大不了的,但我有C语言背景,所以它不会打扰我)