如何深入复制Ruby中的Proc?

时间:2021-04-21 22:03:39

Is there a straightforward way in Ruby to produce a copy of a Proc?

Ruby中是否有直接的方法来生成Proc的副本?

I have a Proc called @foo. I want another method to periodically augment @foo with additional logic. For example:

我有一个叫做@foo的Proc。我想要另一种方法来定期用额外的逻辑来增加@foo。例如:

# create initial Proc
@foo = lambda { |x| x }

# augment with more logic
@foo = lambda { |x| x > 1 ? x*x : @foo[x] }

I don't want the second line that does the augmentation to produce a recursive function. Instead, I want @foo to be bound by value into the lexical scope of the new @foo definition, producing a function that looks more like this:

我不希望进行扩充的第二行产生递归函数。相反,我希望@foo被值绑定到新的@foo定义的词法范围,产生一个看起来更像这样的函数:

@foo = lambda { |x| x > 1 ? x*x : lambda{ |x| x }[x] }

I get an infinite recursion and an eventual stack overflow instead, due to the resulting function looking like this:

我得到一个无限递归和最终的堆栈溢出,因为结果函数看起来像这样:

@foo = lambda { |x| x > 1 ? x*x : lambda { |x| x > 1 ? x*x : { lambda |x| # etc...

I'd like the code to be like this:

我希望代码是这样的:

# augment with more logic
@foo = lambda { |x| x > 1 ? x*x : (@foo.clone)[x] }

but clone doesn't work on Procs.

但是克隆在Procs上不起作用。

Additionally, the standard Ruby deep copy hack, using marshal and unmarshal, doesn't work on Procs either. Is there some way to do this?

此外,使用marshal和unmarshal的标准Ruby深度复制hack也不适用于Procs。有办法做到这一点吗?

1 个解决方案

#1


7  

Even if clone would work on Procs, it wouldn't help you, because you'd still be calling clone on the new value of @foo, not on the previous one like you want.

即使clone可以在Procs上运行,它也无济于事,因为你仍然会在@foo的新值上调用clone,而不是像你想要的那样在前一个上调用clone。

What you can do instead is just store the old value of @foo in a local variable that the lambda can close over.

你可以做的只是将@foo的旧值存储在lambda可以关闭的局部变量中。

Example:

def augment_foo()
  old_foo = @foo
  @foo = lambda { |x| x > 1 ? x*x : old_foo[x] }
end

This way old_foo will refer to the value that @foo had when augment_foo was called and everything will work as you want.

这样old_foo将引用@foo在调用augment_foo时所具有的值,并且一切都将按您的意愿工作。

#1


7  

Even if clone would work on Procs, it wouldn't help you, because you'd still be calling clone on the new value of @foo, not on the previous one like you want.

即使clone可以在Procs上运行,它也无济于事,因为你仍然会在@foo的新值上调用clone,而不是像你想要的那样在前一个上调用clone。

What you can do instead is just store the old value of @foo in a local variable that the lambda can close over.

你可以做的只是将@foo的旧值存储在lambda可以关闭的局部变量中。

Example:

def augment_foo()
  old_foo = @foo
  @foo = lambda { |x| x > 1 ? x*x : old_foo[x] }
end

This way old_foo will refer to the value that @foo had when augment_foo was called and everything will work as you want.

这样old_foo将引用@foo在调用augment_foo时所具有的值,并且一切都将按您的意愿工作。