在 Ruby 中定义一个作为闭包的方法

2023-12-27

我正在 ruby​​ 中的对象中重新定义方法,并且我需要新方法作为闭包。例如:

def mess_it_up(o)
  x = "blah blah"

  def o.to_s
    puts x  # Wrong! x doesn't exists here, a method is not a closure
  end
end

现在如果我定义一个 Proc,它就是一个闭包:

def mess_it_up(o)
  x = "blah blah"

  xp = Proc.new {||
    puts x  # This works
  end

  # but how do I set it to o.to_s.

  def o.to_s
    xp.call  # same problem as before
  end
end

有什么想法如何去做吗?

Thanks.


这有效(在 irb 中测试):

注意:这只改变str- 并非所有 String 实例。请阅读下文以详细了解其为何有效

another_str = "please don't change me!"
str =         "ha, try to change my to_s! hahaha!"
proc = Proc.new { "take that, Mr. str!" }

singleton_class = class << str; self; end

singleton_class.send(:define_method, :to_s) do
  proc.call
end

puts str.to_s         #=> "take that, Mr. str!"
puts another_str.to_s #=> "please don't change me!"

# What! We called String#define_method, right?

puts String           #=>  String
puts singleton_class  #=>  #<Class:#<String:0x3c788a0>>

# ... nope! singleton_class is *not* String
# Keep reading if you're curious :)

这是有效的,因为你正在打开 str单例类 http://www.contextualdevelopment.com/articles/2008/ruby-singleton并在那里定义一个方法。因为这个,以及对模块#define_method http://ruby-doc.org/core/classes/Module.html#M001654,具有一些人所说的“平面范围”,您可以访问如果使用则超出范围的变量def to_s; 'whatever'; end.

您可能想在这里查看一些其他“元编程咒语”:

media.pragprog.com/titles/ppmetr/spells.pdf http://media.pragprog.com/titles/ppmetr/spells.pdf


为什么只是改变str?

因为 Ruby 有一些有趣的技巧。在 Ruby 对象模型中,方法调用导致接收者不仅搜索它的类(而且it's祖先),而且它也是单例类(或者如 Matz 所说,它是特征类)。这个单例类允许您[重新]定义单个对象的方法。这些方法称为“单例方法”。在上面的示例中,我们就是这样做的 - 定义一个单例方法名称to_s。它的功能与此相同:

def str.to_s
  ...
end

唯一的区别是我们在调用时使用闭包Module#define_method, 然而def是一个关键字,它会导致范围的变化。

为什么不能简单一点呢?

好消息是您正在使用 Ruby 进行编程,所以请随意疯狂:

class Object
  def define_method(name, &block)
    singleton = class << self; self; end
    singleton.send(:define_method, name) { |*args| block.call(*args) }
  end
end


str = 'test'
str.define_method(:to_s) { "hello" }
str.define_method(:bark) { "woof!" }
str.define_method(:yell) { "AAAH!" }

puts str.to_s #=> hello
puts str.bark #=> woof!
puts str.yell #=> AAAH!

而且,如果你好奇……

你知道类方法吗?或者,在某些语言中,我们将它们称为静态方法?嗯,那些没有really存在于 Ruby 中。在 Ruby 中,类方法实际上只是 Class 对象的单例类中定义的方法。

如果这一切听起来很疯狂,请查看我上面提供的链接。只有知道如何进行元编程,才能充分利用 Ruby 的强大功能 - 在这种情况下,您确实想了解单例类/方法,更一般地说,了解 Ruby 对象模型。

HTH

-Charles

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Ruby 中定义一个作为闭包的方法 的相关文章

随机推荐