ruby - 我可以在自身的上下文中创建一个过程吗?

标签 ruby closures proc

由于 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/

相关文章:

ruby - 我可以创建一个简单的网站来接受输入和显示,而无需 Rails、数据库或外部 Web 服务器吗?

css - 使用 CSS 属性从 Sprite 裁剪 Logo

javascript - 循环中的套接字 io 和闭包

ruby !方法或过程

ruby - ||= 在 Ruby 线程中安全吗?

ruby - 在 Mechanize 中使用 URI 方法#link

groovy - 为了让 groovy 闭包修改委托(delegate)范围内定义的变量,您是否需要显式指定 delegate.theVariableName?

javascript - 确切的关闭是什么?

tcl - 无法在 TCL 中调用 proc 命令名称无效

ruby - 如何使用带参数的 lambda 来收集数组?