gpt4 book ai didi

Ruby - define_method 和闭包

转载 作者:数据小太阳 更新时间:2023-10-29 07:53:47 24 4
gpt4 key购买 nike

define_method 表现出以下行为:

class TestClass
def exec_block(&block) ; yield ; end
end
TestClass.new.send(:exec_block) do ; puts self ; end
# -> main
TestClass.send(:define_method, :bing) do ; puts self ; end
TestClass.new.bing
# -> <TestClass:...>

我不明白的是传递给 define_method 的 block 应该是一个闭包。因此,它应该(至少根据我的理解)捕获 self 的值。作为main ,如调用时所示exec_block .

我知道该 block 将成为方法的主体,但我不明白该行为的原因。为什么当使用不同的方法时, block 会评估不同的东西?

如何使用 define_method 重现 block 的行为?对于其他方法?即我怎么写 exec_block让它输出 <TestClass:...>而不是“主要”?

最佳答案

self 像任何其他变量一样被闭包捕获。我们可以通过围绕不同的对象实例传递 Proc 来验证:

class A
def exec_block(&block)
block.call
end
end

class B
def exec_indirect(&block)
A.new.exec_block(&block)
end
end

block = proc { p self }
a = A.new; b = B.new

a.exec_block(&block) # => main
b.exec_indirect(&block) # => main

然而,BasicObject#instance_eval并且类似的动态重新绑定(bind) self 变量:

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

Module#define_method依次使用 instance_eval 来执行关联的 block :

If a block is specified, it is used as the method body. This block is evaluated using instance_eval [...]

观察:

A.send(:define_method, :foo, &block)
a.foo # => #<A:0x00000001717040>
a.instance_eval(&block) # => #<A:0x00000001717040>

有了这些知识,您现在可以重写您的 exec_block 以使用 instance_eval:

class A
def exec_block(&block)
instance_eval(&block)
end
end

block = proc { p self }
A.new.exec_block(&block) # => #<A:0x00000001bb9828>

如前所述,使用 instance_eval 似乎是运行具有修改上下文的 Proc 实例的唯一方法。它可以用于 implement dynamic binding在 Ruby 中。

关于Ruby - define_method 和闭包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10206193/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com