如何在`&`-`和`往返下保留proc对象?

saw*_*awa 5 ruby proc

当我将一个数组*传递给一个方法,然后*在该方法中重建一个数组时,不保留数组的标识:

a = []
a.object_id # => 69846339548760
def bar *a; a.object_id end
bar(*a) # => 69846339537540
Run Code Online (Sandbox Code Playgroud)

但是,当我将proc转换为块&时将其传递给方法,然后&在方法中从块重构proc,则proc 的标识似乎会被保留:

pr = ->{}
pr.object_id # => 69846339666160
def foo ≺ pr.object_id end
foo(&pr) # => 69846339666160
Run Code Online (Sandbox Code Playgroud)

proc对象是如何保留的?它转换成块时不会丢失吗?这是一种保证行为吗?

Vas*_*fed 2

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  
Run Code Online (Sandbox Code Playgroud)

当将 proc 作为块传递时,会发生类似的情况,但 ruby​​ 不必解开 proc,它已经是一个 proc。

添加:根据 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
Run Code Online (Sandbox Code Playgroud)

这是某种标准化的行为,所以至少 Rubinius 和 jRuby 应该遵循