我在 Julia 中有以下代码
global a::Int = 0 #global variable
function f(x)
return a*x
end
function g(y)
global a = 2
b = f(2)
return b
end
这不是确切的代码,但想法是相同的。在这段代码中,当计算 g(y) 中的 f(2) 时,使用的 a 值是原始 a = 0,而不是更新后的值 a = 2。你知道如何解决这个问题吗? ?
我尝试传递 a 作为参数并且它有效,但我想保留函数 f 而不需要额外的参数作为输入。
考虑到需要全局变量的情况,经过语法和打印行编辑的代码似乎可以正常工作。要检查这一点,请在
GLOBALVAR
中写入全局变量 g(...)
重新分配之前和之后。
#set the global variable to zero.
global GLOBALVAR = Int(0)
#f(x) references the global variable, but doesn't modify it.
function f(x)
return GLOBALVAR*x
end
#g(x) modifies the global variable.
function g(y)
global GLOBALVAR = 2
b = f(2)
return b
end
println("Before g(x) call: \n GLOBALVAR = $GLOBALVAR \n f(2) = $(f(2))")
g(2);
println("After g(x) call: \n GLOBALVAR = $GLOBALVAR \n f(2) = $(f(2))")
julia>
Before g(x) call:
GLOBALVAR = 0
f(2) = 0
After g(x) call:
GLOBALVAR = 2
f(2) = 4
全局变量已更新。
全局变量会给你带来一些麻烦。它们通常可读性较差,有时性能也较差。我们可能想要重构以排除它们的使用。
一个显着的区别是,在 Julia 中,数字是“不可变的”。像这样的函数
function setToZero!(n::Int)
n = 0
return n
end
num = 10
println("before: $num")
setToZero!(num)
println("after: $num")
julia>
before: 10
after: 10
无法按预期运行,因为分配 n 不会改变原始变量。有许多可变类型,一个简单的解决方法是 Vector中的值是可变的。
请记住,有很多解决方案,例如 Ref
或完全创建新的可变结构。这样,我们就可以用以下方法重构您的原始代码:
f(x, val::Vector) = val[1]*x
function g!(y, val::Vector)
val[1] = 2
return f(2, val)
end
changingVal = [0]
println("Before g!(...) call: \n changingVal = $changingVal \n f(2,changingVal) = $(f(2,changingVal))")
g!(2, changingVal);
println("Before g!(...) call: \n changingVal = $changingVal \n f(2,changingVal) = $(f(2,changingVal))")
julia>
Before g!(...) call:
changingVal = [0]
f(2,changingVal) = 0
Before g!(...) call:
changingVal = [2]
f(2,changingVal) = 4
当然,与仅创建单个全局 Int 相比,创建向量的空间和时间效率会更低,因此在这个简化的示例中,“非全局”版本将“显着”变慢。在较大的程序中这可能是也可能不是,但这两种方式都是有效的。