定义一个在Ruby中是闭包的方法 [英] Define a method that is a closure in Ruby

查看:109
本文介绍了定义一个在Ruby中是闭包的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在ruby中的一个对象中重新定义一个方法,我需要一个新的方法是一个闭包。例如:

  def mess_it_up(o)
x =blah blah

def o.to_s
puts x#错误! x不存在这里,一个方法不是一个闭包
end
end

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

  def mess_it_up(o)
x =blah blah

xp = Proc.new {||
puts x#这工作
end

#但是如何设置为o.to_s。

def o.to_s
xp.call#和以前一样的问题
end
end
任何想法如何做?



谢谢。

解决方案

这样工作(在irb测试):



注意:这只改变 str - 不是所有的String实例。请阅读下文,了解为什么会有效

  another_str =请不要改变我! 
str =ha,尝试改变我的to_s!hahaha!
proc = Proc.new {take that,Mr. str! }

singleton_class = class<< str;自; end

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

puts str.to_s#=> 拿那个,先生!
puts another_str.to_s#=> 请不要改我!

#什么!我们调用String#define_method,对吧?

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

#... nope! singleton_class is * not * String
#如果你好奇,继续阅读:)

因为您正在打开str的单身课,并在其中定义方法。因为这一点,以及对 Module#define_method 的调用,有些人称为平面范围,你可以访问超出范围的变量,如果你使用 def to_s; '随你';结束



您可能想在这里查看其他一些元编程法术:



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





为什么只更改 str strong>



因为Ruby有一些有趣的技巧,它的袖子。在Ruby对象模型中,方法调用导致接收者不仅搜索它的类(以及它的祖先),而且搜索单例类(或者Matz称之为eigenclass)。这个单例类是什么允许你为单个对象定义一个方法。这些方法称为单例方法。在上面的例子中,我们做的只是 - 定义一个单例方法名称 to_s 。它的功能与此相同:

  def str.to_s 
...
end

唯一的区别是,当调用 Module#define_method ,而 def 是一个关键字,导致范围的更改。



为什么不能更简单?



好吧,好消息是,你使用Ruby编程,所以你可以疯狂: p>

  class Object 
def define_method(name,& block)
singleton = class<自;自; 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#=>纬!
puts str.yell#=> AAAH!

如果你好奇...

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



如果这听起来很疯狂,看看我上面提供的链接。如果你知道如何元编程,很多Ruby的能力只能被挖掘出来 - 在这种情况下你真的想知道单例类/方法,更一般的是Ruby对象模型。



HTH



-Charles


I'm re-defining a method in an object in ruby and I need the new method to be a closure. For example:

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

Now if I define a Proc, it is a closure:

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

Any ideas how to do it?

Thanks.

解决方案

This works (tested in irb):

NOTE: This changes only str - not all instances of String. Read below for details as to why this works

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 :)

This works because you are opening str's singleton class and defining a method there. Because this, as well as the call to Module#define_method, have what some call a "flat scope", you're able to access variables that would be out of scope if you used def to_s; 'whatever'; end.

You may want to check out some of these other "metaprogramming spells" here:

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


Why does it only change str?

Because Ruby has a couple interesting tricks up it's sleeves. In the Ruby object model, a method invocation results in the reciever searching not only it's class (and it's ancestors), but also it's singleton class (or as Matz would call it, it's eigenclass). This singleton class is what allows you to [re]define a method for a single object. These methods are called "singleton methods". In the example above, we are doing just that - defining a singleton method name to_s. It's functionaly identical to this:

def str.to_s
  ...
end

The only difference is that we get to use a closure when calling Module#define_method, whereas def is a keyword, which results in a change of scope.

Why can't it be simpler?

Well, the good news is that you're programming in Ruby, so feel free to go crazy:

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!

And, if you're curious...

You know class methods? Or, in some languages, we'd call them static methods? Well, those don't really exist in Ruby. In Ruby, class methods are really just methods defined in the Class object's singleton class.

If that all sounds crazy, take a look at the links I provided above. A lot of Ruby's power can only be tapped into if you know how to metaprogram - in which case you'll really want to know about singleton classes/methods, and more generally, the Ruby object model.

HTH

-Charles

这篇关于定义一个在Ruby中是闭包的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆