web-dev-qa-db-ja.com

参照によるJulia関数の引数

ドキュメントは言う

Juliaでは、関数へのすべての引数は参照によって渡されます。

したがって、これら2つの関数の動作の違いを見て非常に驚きました。

function foo!(r::Array{Int64})                                                                                                                                                                                     
        r=r+1                                                                                                                                                                                                      
end


function foobar!(r::Array{Int64})                                                                                                                                                                                  
        for i=1:length(r)                                                                                                                                                                                          
                r[i]=r[i]+1                                                                                                                                                                                        
        end                                                                                                                                                                                                        
end 

予想外に異なる出力は次のとおりです。

Julia> myarray
2-element Array{Int64,1}:
 0
 0

Julia> foo!(myarray);

Julia> myarray
2-element Array{Int64,1}:
 0
 0

Julia> foobar!(myarray);

Julia> myarray
2-element Array{Int64,1}:
 1
 1

配列が参照によって渡された場合、私はfooを期待していました!ゼロを1に変更します。

14
Lindon

r=r+1Assignmentステートメントです。これは、rを再割り当てすることを意味するため、親スコープ内のペアを参照しなくなります。だが r[i]=r[i]+1Mutatesr値、突然変異は割り当てとは異なります( ここでの適切な説明 )、その後rは、親スコープ内のペア変数を引き続き参照します。

19
Reza Afzalan

ここの文書は少し曖昧だと思います。

厳密に言えば、Juliaは、Python、Java、Ruby、jsなどのほとんどの言語で使用される「値による呼び出し」または「共有による呼び出し」です...を参照してください wiki

参照動作による呼び出しは、実際にfoo!ゼロを1に変更します。ただし、ジュリアはそれをサポートしていません。 (C#を知っている場合は、それがrefまたはoutの機能です)

8
colinfang

配列内の各変数を変更するために、ブロードキャスト.操作が使用できます。ただし、配列内の各値は等しく変更されるため、forループは必要ないことに注意してください。

配列の各要素に1を追加する場合:

a = Rand(1:10, 10)
show(a) = [4, 8, 9, 1, 4, 2, 6, 7, 1, 5]

function add1!(a::Array{Int64})
    a .= a .+ 1
end

add1!(a);
show(a) = [5, 9, 10, 2, 5, 3, 7, 8, 2, 6]

それにもかかわらず、配列の各値を個別に変更する必要がある場合は、インデックスを使用したforループが避けられません。

2
Kadir Gunel

実際には、前の回答で説明した理論(call _by sharing_)に関係なく、配列としてのポインター変数が_by reference_を渡され、数値などのスカラー変数が_by value_。

これは、パラメーターが_by value_または_by reference_の場合、関数宣言の正式なパラメーター部分で指定するCまたはPascal言語に慣れている私のような人々にとっては苦痛です。

ただし、関数で複数の値を返すことができるJuliaの機能により、スカラー変数のパラメーター_by reference_をシミュレートする洗練された方法があります。変数が再作成されるため、これは文字列などの不変の変数に対しても機能することは明らかです。

ジュリアのコード

_function process(a,b,c)
  a += c 
  b *= c
  return a*b*c, a, b  # normal result, changing "a" and "b"
end

a = 4
b = 7
println("Before: ", a," ",b)
result, a, b = process(a,b,7)
println("After: ", a," ",b," ", result)
_

表示

_Before: 4 7
After: 11 49 3773 
_

abは両方とも関数プロセス内で変更されました。 aが7に追加され、bに7が掛けられました

1
Paulo Buchsbaum