如何在“&”-“&”往返下保存 proc 对象?
How is a proc object preserved under `&`-`&` roundtrip?
当我在将数组传递给方法时用 *
展开一个数组,然后在方法中用 *
从它重建一个数组,数组的身份没有被保留:
a = []
a.object_id # => 69846339548760
def bar *a; a.object_id end
bar(*a) # => 69846339537540
然而,当我将一个过程变成一个带有 &
的块时将它传递给一个方法,然后在方法中从带有 &
的块重建一个过程,过程的身份似乎被保留:
pr = ->{}
pr.object_id # => 69846339666160
def foo ≺ pr.object_id end
foo(&pr) # => 69846339666160
proc 对象是如何保存的?转成block不就丢了吗?这是有保证的行为吗?
Ruby VM 是堆栈计算机。当调用一个函数时,它会将它的所有参数(包括self
)放入堆栈,然后调用。
array splat 的工作原理 - 它获取数组内容并将其放入堆栈,然后调用函数:
> 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: -1@-1, 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 作为一个块传递时,会发生类似的事情,但是 ruby 不必解包 proc,它已经是一个 proc。
添加: 根据 Ruby 规范的 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
这是某种标准化的行为,因此至少应该遵循 Rubinius 和 jRuby
当我在将数组传递给方法时用 *
展开一个数组,然后在方法中用 *
从它重建一个数组,数组的身份没有被保留:
a = []
a.object_id # => 69846339548760
def bar *a; a.object_id end
bar(*a) # => 69846339537540
然而,当我将一个过程变成一个带有 &
的块时将它传递给一个方法,然后在方法中从带有 &
的块重建一个过程,过程的身份似乎被保留:
pr = ->{}
pr.object_id # => 69846339666160
def foo ≺ pr.object_id end
foo(&pr) # => 69846339666160
proc 对象是如何保存的?转成block不就丢了吗?这是有保证的行为吗?
Ruby VM 是堆栈计算机。当调用一个函数时,它会将它的所有参数(包括self
)放入堆栈,然后调用。
array splat 的工作原理 - 它获取数组内容并将其放入堆栈,然后调用函数:
> 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: -1@-1, 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 作为一个块传递时,会发生类似的事情,但是 ruby 不必解包 proc,它已经是一个 proc。
添加: 根据 Ruby 规范的 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
这是某种标准化的行为,因此至少应该遵循 Rubinius 和 jRuby