2016-01-29 5 views
5

メソッド内*と、そこからアレイを再構築、配列の同一性が保存されていない次いで、メソッドに渡すときに、私は*を配列スプラット:procオブジェクトは `&` -`& `roundtripの下でどのように保持されますか?

a = [] 
a.object_id # => 69846339548760 
def bar *a; a.object_id end 
bar(*a) # => 69846339537540 

をしかし、私は電源を入れたときメソッドに渡すとき&とブロックにprocが、その後、メソッド内&でブロックからPROCを再構築、PROCのアイデンティティが維持されているようだ:

pr = ->{} 
pr.object_id # => 69846339666160 
def foo ≺ pr.object_id end 
foo(&pr) # => 69846339666160 

PROCオブジェクトが保存されている方法は?それはブロックに変換されたときに失われていないのですか?これは保証された行動ですか?

+1

を続けなければならない。少なくともこれは、やや標準化された行動であるRubySpecのhttps://github.com/ruby/spec/blob/master/core/proc/block_pass_spec.rb

def revivify; Proc.new; end it "remains the same object if re-vivified by the target method" do p = Proc.new {} p2 = revivify(&p) p.object_id.should == p2.object_id p.should == p2 end 

あたりとして: 'DEFバズ。 Proc.new.object_idを終了します。 p = - > {}; p.object_id#⇒9708320; baz &p ;#⇒9708320' – mudasobwa

+0

@mudasobwaこれは特別な構文規則のためです。メソッド内でブロックなしでprocを作成する場合は、そのメソッドに渡されたprocを参照します。 – sawa

+0

私は知っています、ありがとう。私は 'Proc.new'は実際にはコンストラクタではないことを意味しました_。 – mudasobwa

答えて

2

Ruby VMはスタックマシンです。関数を呼び出すときには、すべての引数(selfを含む)をスタックに入れて呼び出します。

> puts RubyVM::InstructionSequence.compile("a = []; func *a").disasm 
== disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>========== 
local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: [email protected], kwrest: -1]) 
[ 2] a   
0000 trace   1            ( 1) 
0002 newarray   0 
0004 setlocal_OP__WC__0 2 
0006 putself   
0007 getlocal_OP__WC__0 2 
0009 splatarray  false 
0011 opt_send_without_block <callinfo!mid:func, argc:1, ARGS_SPLAT|FCALL> 
0013 leave 

ブロックとしてPROCを渡すとき、同じようなことが起こるが、ルビーはPROCをアンラップする必要はありません。これは、配列の内容を取り、スタックにそれを置く、その関数を呼び出す - 配列のスプラットの仕組み

、それはすでにprocです。

を追加しました:さらにRubiniusのとJRubyの

+1

これは、MRI、JRuby、Rubiniusなどを使用しているかどうかによって、この質問に対する答えが異なることを意味しますか? –

+1

@JoshRumbut ruby​​specはこの動作を定義しているので、同じ動作にする必要があります – Vasfed

関連する問題