【问题标题】:How to change self in a block like instance_eval method do?如何在像 instance_eval 方法这样的块中更改 self 呢?
【发布时间】:2012-02-27 06:09:51
【问题描述】:

instance_eval 方法在其块中改变自身,例如:

class D; end
d = D.new
d.instance_eval do
  puts self  # print something like #<D:0x8a6d9f4>, not 'main'!
end

如果我们自己定义一个方法(或任何其他方法(除了instance_eval),它需要一个块),当打印self时,我们将得到'main',这与instance_eval方法不同。例如:

[1].each do |e|
  puts self  # print 'main'
end

我如何定义像 instance_eval 这样的方法(需要一个块)? 提前致谢。

【问题讨论】:

  • 你想达到什么目标?
  • 我认为不可能做你想做的事。可能是因为如果你能自己改变自己,那就太混乱了。

标签: ruby metaprogramming self


【解决方案1】:

您可以编写一个接受 proc 参数的方法,然后将其作为 proc 参数传递给 instance_eval。

class Foo
  def bar(&b)
    # Do something here first.
    instance_eval &b
    # Do something else here afterward, call it again, etc.
  end
end

Foo.new.bar { puts self }

产量

#<Foo:0x100329f00>

【讨论】:

  • 我明白你的意思,但没有解决我的问题。我想定义一个像 instance_eval 这样的方法,而不是使用 instance_eval。我想要实现而不是包装器。谢谢大家!
  • 那么,您需要更具体地了解您想要实现的目标。如果您只是想要一个可以接受块的方法,然后在与您的方法相同的上下文中执行一次或多次,那么这样做。如果我不得不猜测,也许您也想将参数传递给块?我知道这是可能的,因为 RSpec 做到了,而且这个例子确实没有。我应该看看 RSpec 代码,看看他们是怎么做的。
  • 实际上,我看到 RSpec 没有将参数传递给块,它使用 instance_eval 来调用块。请参阅rubydoc.info/gems/rspec-core/RSpec/Core/… 并点击“查看源代码”。
  • 我是中国人,英文表达不好!实际上我想知道 instance_eval 的实现细节,可能是纯 ruby​​ 无法实现,也许只有 C 才能实现目标(更改评估它的块上下文)。如果没有合适的,我会尽快关闭问题答案。
  • 我仍然不明白为什么重新实现 instance_eval 比简单地通过调用它来获取它的行为更有用。如果您想了解 Ruby 中的任何内容是如何实现的,可以从 apidock.com/ruby 开始。找到您感兴趣的方法(在本例中为apidock.com/ruby/Object/instance_eval),然后单击“显示源”。果然,这个方法的实现是用 C 语言实现的,所以你需要下载 Ruby 的源代码来进一步探索。
【解决方案2】:

很明显:

class Object
  def your_method(*args, &block)
    instance_eval &block
  end
end

receiver = Object.new

receiver.your_method do
  puts self  #=> it will print the self of receiver
end

【讨论】:

  • 对不起,我想要的是一个方法,它需要一个块,并在那个块中将 self 更改为接收器,就像 instance_eval 一样!
猜你喜欢
  • 1970-01-01
  • 2012-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-21
  • 2013-06-21
  • 1970-01-01
相关资源
最近更新 更多