我对 Julia 的参数传递理解

起因

我之前一直没有搞懂 Julia 的参数到底是怎么传的(自然 Python 我也就没有懂),不知道何时会改变参数的值,何时不会。最近在学 C语言,明显感到传参很清晰,就是传值,要改变函数外面的对象,就传指针进去。因此为了搞懂 Julia 到底是怎么传参数的(我以前有些函数写得莫名其妙,因为不知道会不会改变传入的对象),又去翻了文档,可惜没看懂。

Julia 函数参数遵循有时称为 “pass-by-sharing” 的约定,这意味着变量在被传递给函数时其值并不会被复制。函数参数本身充当新的变量绑定(指向变量值的新地址),它们所指向的值与所传递变量的值完全相同。调用者可以看到对函数内可变值(如数组)的修改。这与 Scheme,大多数 Lisps,Python,Ruby 和 Perl 以及其他动态语言中的行为相同。

尝试

当我尝试去搜索 pass-by-sharing 的时候,其实并没有太合适的结果,直到昨天,我又一次去搜索,点进有可能的结果里面一个个看,看到了 这篇文章 深入探討 JavaScript 中的參數傳遞:call by value 還是 reference?, 就有点懂了,发现叫 call by sharing. 最后一下就搜索出来了。(现在再次搜索发现是我把第一个搜索结果 Evaluation strategy 给忽略了,它里面基本上讲明白了。 :sweat_smile:

我的理解

看了文章与 wiki 之后感觉有点明白了。我的理解是这样的,不知道对不对。

如果是对对象整体进行的操作,就不会改变原始的对象,但是如果是直接修改对象的部分,就会改变原来的对象。

举例

x=reshape(collect(1:9),3,3)
function f(x)
    x=x^2
end
println(f(x)) #[30 66 102; 36 81 126; 42 96 150]
println(x)  #[1 4 7; 2 5 8; 3 6 9]

此处 x 不变,是因为 函数内的 x 和外面的 x 共享同一个对象,后来 x=x^2 给函数内的 x 重新赋值,它不再共享函数外面的 x 的那个对象, 我们也没有修改那个对象。因此,外面的 x 没有改变。

用指针的思路来理解的话,就是 函数内的 x 确实指向 函数外的 x 的那个对象,但是在 x=x^2 这里,它指向了中间生成的临时变量 x^2, 不再指向函数外部的 x. 因此 函数外部的 x 不变。

x=reshape(collect(1:9),3,3)
function g(x)
    x.=x^2
end
println(g(x)) #[30 66 102; 36 81 126; 42 96 150]
println(x) #[30 66 102; 36 81 126; 42 96 150]

这里我的理解是,x^2 生成了一个新的矩阵, 然后 x .= x^2 相当于是

y=x^2
for i in eachindex(x)
    x[i]=y[i] # 这里按位置修改了 x的值。
end

这里,我们直接修改了函数内的 x 所共享的对象,由于函数内外的两个 x 共享同一个对象,因此外面的 x 也被改变了。

按照指针的思路来理解的话,就是我们先创建了一个临时变量 y=x^2, 然后通过指针,将 x 上的值一个个变成y 的值。最后 函数外的x 自然就变了。

写在最后

以上是个人理解,感觉其实并不是十分准确,希望有明白的人能够再讲的细一点。这样我就知道,我到底什么时候该给函数加上! 了(因为有时候函数并不按照我想的那样修改了参数的值。)

1赞

我开始也是觉得很不习惯。在R中基本上直接用<- 或者= 就直接传值过来。
个人感觉传指针应该是减少不必要的内存消耗。不过有时候也容易引起混乱。
大部分情况下如果需要传值的话我会用y = copy(x)这样的方式。

京ICP备17009874号-2