【问题标题】:Julia scoping: why does this function modify a global variable?Julia 作用域:为什么这个函数会修改全局变量?
【发布时间】:2020-06-23 12:20:28
【问题描述】:

我是 Julia 的新手,到目前为止我是它的粉丝。但是从多年的 R 编程经验来看,一些范围规则让我感到困惑。

让我们使用这个函数。这完全符合我的预期。

function foo1(x)
    y = x
    t = 1
    while t < 1000
      t += 1
      y += 1
    end
    return 42
end

var = 0;
foo1(var)
# 42
var
# 0

但是在对数组执行类似操作时,它会充当变异函数(在全局范围内修改它的参数!)

function foo2(x)
    y = x
    t = 1    
    while t < 1000
      t += 1
      y[1] += 1
    end
    return 42
end

var = zeros(1);
foo2(var)
# 42
var
# 999.0

我意识到我可以通过将第一行更改为 y = copy(x) 来解决此问题,但首先出现这种(危险?)行为的原因是什么?

【问题讨论】:

标签: function arguments julia scoping


【解决方案1】:

我会为此写一个答案,但我认为 John Myles White 已经做得比我做得更好,所以我将链接到他的博文:

https://www.juliabloggers.com/values-vs-bindings-the-map-is-not-the-territory-3/

简而言之,x = 1x[1] = 1 是非常不同的操作。第一个是分配——即更改变量x 的绑定——而第二个是调用setindex! 函数的语法糖,在数组的情况下,该函数分配给数组中的一个位置。赋值只会改变哪些变量引用了哪些对象,而不会修改任何对象。变异只修改对象,从不改变哪些变量引用了哪些对象。这个答案有更多关于区别的细节:Creating copies in Julia with = operator

【讨论】:

  • 简而言之,x = 1x[1] = 1 是非常不同的操作。第一个是赋值(更改x 的绑定),而第二个是setproperty! 函数的语法糖。
  • 感谢您的指点,确实很有启发性。我对帖子的语气感到惊讶,这似乎暗示修改函数的参数是可取的。我想我需要忘记 Julia 中的函数式编程(“无副作用”)并接受效率。
  • 约定是,如果一个函数改变了它的参数,函数名应该以!结尾,以警告用户。函数通常具有变异和纯函数变体,以便在必要时提高效率,但默认情况下提供更安全、非变异的行为。
  • 太好了,感谢您的澄清。在 Julia 中编写安全、功能纯函数然后首先copy() 可能在函数体中修改的参数是正确的方法吗?
  • 如果你有一个最容易表达和/或就地执行最有效的算法,那就这样做吧!将其定义为function algorithm!(x) ... end。然后,如果有意义,您可以定义辅助 algorithm(x) = algorithm!(copy(x))
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-25
  • 1970-01-01
相关资源
最近更新 更多