由于 proc 是一个对象,我可以在它自己的实例范围内创建一个 proc 吗?
例如:
prc = Proc.new do
foo
end
def prc.foo
123
end
prc.call
# NameError: undefined local variable or method `foo' for main:Object
通过更改 self
或通过显式 receiver
引用 proc。该接收器必须动态评估,例如以下应该有效:
other_prc = prc.clone
def other_prc.foo
456
end
other_prc.call
#=> 456 <- not 123
这意味着我不能只是通过以下方式“硬编码”它:prc = Proc.new do
prc.foo
end
换句话说:有没有办法从 proc 中引用 procs 实例?另一个没有
foo
的例子:(为 # ???
放什么)prc = Proc.new do
# ???
end
prc == prc.call #=> true
other_prc = prc.clone
other_prc == other_prc.call #=> true
用 # ???
替换 prc
只会满足 prc == prc.call
而不是 other_prc == other_prc.call
。 (因为 other_prc.call
仍然会返回 prc
)
最佳答案
免责声明:我正在回答我自己的问题
解决方案非常简单。只需覆盖 call
通过 instance_exec
调用 proc :
Executes the given block within the context of the receiver (obj). In order to set the context, the variable
self
is set to obj while the code is executing, giving the code access to obj's instance variables. Arguments are passed as block parameters.
prc = proc { |arg|
@a ||= 0
@a += 1
p self: self, arg: arg, '@a': @a
}
def prc.call(*args)
instance_exec(*args, &self)
end
在这里,接收者是过程本身,“给定 block ”也是过程本身。 instance_exec
因此将在其自己的实例的上下文中调用 proc。它甚至会传递任何额外的参数!使用上述:
prc
#=> #<Proc:0x00007f84d29dcbb0>
prc.call(:foo)
#=> {:self=>#<Proc:0x00007f84d29dcbb0>, :arg=>:foo, :@a=>1}
# ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^
# correct object passes args
prc.call(:bar)
#=> {:self=>#<Proc:0x00007f84d29dcbb0>, :arg=>:bar, :@a=>2}
# ^^^^^^
# preserves ivars
prc.instance_variable_get(:@a)
#=> 2 <- actually stores ivars in the proc instance
other_prc = prc.clone
#=> #<Proc:0x00007f84d29dc598>
# ^^^^^^^^^^^^^^^^^^
# different object
other_prc.call(:baz)
#=> {:self=>#<Proc:0x00007f84d29dc598>, :arg=>:baz, :@a=>3}
# ^^^^^^
# ivars are cloned
other_prc.call(:qux)
#=> {:self=>#<Proc:0x00007f84d29dc598>, :arg=>:qux, :@a=>4}
prc.call(:quux)
#=> {:self=>#<Proc:0x00007f84d29dcbb0>, :arg=>:quux, :@a=>3}
# ^^^^^^
# both instances have separate ivars
关于ruby - 我可以在自身的上下文中创建一个过程吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62738704/