2016-08-31 5 views
2

Is ruby pass by reference or value?を読んだ後、私はたくさんのことを学んだことがありますが、私はそれを読んでいたよりも多くの質問が残っています。このRubyの例の値渡しの理解

まず、グローバルスコープbazに値を持っています

はここ

def foo(bar) 
    bar = 'reference' 
end 
baz = 'value' 
foo(baz) 
puts "Ruby is pass-by-#{baz}" 

出力 Ruby is pass-by-value

が、これがどのように機能するかを詳細に分析する私の試みである、次の例を考えてみましょうvalue

ここでfooは、パラメータを受け取り、それに渡すものはすべてlocalレベルです。我々はbazを渡すとき

したがって、referenceに等しいANOTHER bazがあるが、我々はそれがvalue印刷グローバルレベルでこれを置く場合、これは、結果として、ローカルレベルです。私は上記の言ったことは真実であるならば

今すぐ

def foo(bar) 
    bar.replace 'reference' 
end 
baz = 'value' 
foo(baz) 
puts "Ruby is pass-by-#{baz}" 

出力

Ruby is pass-by-reference

別の例を考えて、ここで.replace方法は、グローバルbazを変更するのですか?私はこれを正しく解釈していますか?私の試みの間違いを指摘してください、私は右のトラックに私の場合は手がかりがありません。

ありがとうございます!

EDIT

もっとマジック

def my_foo(a_hash) 
    a_hash["test"]="reference" 
end; 

hash = {"test"=>"value"} 
my_foo(hash) 
puts "Ruby is pass-by-#{hash["test"]}" 

答えて

1

Rubyは値渡しですが、値はオブジェクトへの参照です。

最初の実験では、bazは、"value"という文字列への参照です。 barは、fooに電話するとbazのコピー(つまり、参照のコピー)に初期化されます。barを文字列"reference"への参照で上書きします。 barはコピーであるため、上書きすると変更されませんbaz。あなたの第二の実験で

は、再び、bazあなたがfooを呼び出すとき"value"barbazのコピーに初期化された文字列への参照です。今回は、barを上書きせず、その上でメソッドを呼び出します。 barbazのコピーですが、同じオブジェクト(文字列"value")を参照します。メソッドを呼び出すと、そのオブジェクトの状態が変更されます。次にto_sbaz(間接的には"Ruby is pass-by-#{baz}"に代入)に呼び出し、to_sは新しい状態を返します。

3番目の実験は2番目の実験と大変よく似ています。このメソッドでは、参照のコピーによって参照されるオブジェクトの状態を変更し、メソッド外で元の参照を使用して新しい状態を読み戻します。

+0

方法によって別の魔法の例を追加しました..私の脳のdoesent get it -__- – bill

+0

もう一つの魔法の例を追加しました – bill

+0

'foo'を呼び出すと' bar'が 'baz'のコピーに初期化されません。これはこの最初の瞬間に同じ物体を指しています。 –

0

それは実際のメソッドにパラメータを渡すとは何の関係もありません。私はあなたの例から重要な部分を抽出しました:

baz = 'value' 
bar = baz 
bar = 'reference' 
puts baz 
bar = baz 
bar.replace 'reference' 
puts baz 

あなたは変数をポインタと考えるかもしれません。 =を使用すると、変数のポイントを別のものにし、元の値は変更されず、そのポイントを指す他の変数を介してアクセスできます。しかし、replaceを使用すると、変数が指す文字列の内容が変更されます。

+0

[OK]をつもりはこれと他の回答を見て、私はあなたが完全に第二の実験部分に私を失った – bill

0

最初に、新しいオブジェクトを作成するbar = 'reference'を使用します。 2番目のものでは、適用するオブジェクトを変更します。.replaceあなたは.object_idメソッドによってこれを保証することができます。例:

def foo_eql(bar) 
    bar = 'reference' 
    puts bar.object_id 
    bar 
end 

def foo_replace(bar) 
    bar.replace 'reference' 
    puts bar.object_id 
    bar 
end 

baz = 'value' 
puts baz.object_id #Here you will get original baz object_id 
res1 = foo_eql(baz) #Here you will get printed new object_id 
res2 = foo_replace(baz) #Here you will get printed original baz object_id 
puts "foo_eql: Ruby is pass-by-#{res1}" 
=> foo_eql: Ruby is pass-by-reference 
puts "foo_replace: Ruby is pass-by-#{res2}" 
=> foo_replace: Ruby is pass-by-reference 

したがって、魔法はまったくありません。あなたのハッシュの例では、新しいハッシュオブジェクトを作成せず、既存のハッシュオブジェクトを変更します。しかし、あなたは、このような方法で新しいものを作成することができます。

def my_foo(a_hash) 
    a_hash = a_hash.merge({"test" => "reference"}) 
end 
my_foo(hash) 
puts "Ruby is pass-by-#{hash["test"]}" 

基本的には「」のようにオブジェクトへの参照を渡します。より良い理解のために、this postとそれに対するコメントを確認してください。

1

非常に興味深いものです。 object_id sの

プレイ、あなたはルビーシーン怒鳴るやっていることが表示されます:ローカル割り当てbar = 'reference'

def foo(bar) 
    puts bar.object_id 
    bar = 'reference' 
    puts bar.object_id 
end 

baz = 'value' 
puts baz.object_id 
foo(baz) 

出力

> baz = 'value' 
=> "value" 

> puts baz.object_id 
70241392845040 

> foo(baz) 
70241392845040 
70241392866940 

、ローカル変数bar参照します別のオブジェクトであるため、元のオブジェクトは変更されません。

場合によっては、オブジェクトのdupとなるようです。

+0

と思われます。「置き換えられた」ということは、「object_id」を変更するのはなぜですか?また、あなたはそれを見てみたい場合は、別の例のウィットハッシュを追加しました。 – bill

1

多分これはそれを理解するのに役立ちます:

x = 'ab' 
x.object_id 
=> 70287848748000 # a place in memory 

x = 'cd' 
x.object_id 
=> 70287848695760 # other place in memory (other object) 

x.replace('xy') 
x.object_id 
=> 70287848695760 # the same place in memory (the same object) 
関連する問題