有没有一种方法可以从该实例内部为一个Ruby类的实例创build方法?

让有class Example定义为:

 class Example def initialize(test='hey') self.class.send(:define_method, :say_hello, lambda { test }) end end 

在调用Example.new; Example.new Example.new; Example.new我得到一个warning: method redefined; discarding old say_hello warning: method redefined; discarding old say_hello 。 我的结论是,它必须是因为它在实际的类中定义了一个方法(从语法上讲是有道理的)。 而且,当然,如果在他们的方法中存在具有不同值的Example多个实例,那将certificate是灾难性的。

有没有一种方法可以在该实例内为类的实例创build方法?

您需要获取对实例的单例类的引用,该类包含所有特定于实例的东西,并定义其中的方法。 在ruby1.8,看起来有点凌乱。 (如果你find一个更清洁的解决scheme,让我知道!)

Ruby 1.8

 class Example def initialize(test='hey') singleton = class << self; self end singleton.send :define_method, :say_hello, lambda { test } end end 

但是,Ruby 1.9提供了一个更简单的方法。

Ruby 1.9

 class Example def initialize(test='hey') define_singleton_method :say_hello, lambda { test } end end 

首先,一个小风格的提示:

 self.class.send(:define_method, :say_hello, lambda { test }) 

在Ruby 1.9中使用新的proc文字可以使这看起来更好一点:

 self.class.send(:define_method, :say_hello, -> { test }) 

但是你不需要那个。 Ruby有一些叫块的东西,它们基本上是一段代码,可以作为parameter passing给一个方法。 实际上,你已经使用了块,因为lambda只是一个将块作为参数并返回一个Proc 。 然而, define_method无论如何已经占用了一个块,没有必要将一个块传递给lambda ,它将其转换为一个Proc ,然后将其传递给define_method ,然后将其转换回块:

 self.class.send(:define_method, :say_hello) { test } 

正如你已经注意到的,你正在定义错误类的方法。 你在Example类中定义它,因为在像initialize这样的实例方法中, self是当前对象(即@ mikej示例中的ex1ex2 ),这意味着self.classex1的类,即Example 。 所以,你一遍又一遍地覆盖同样的方法。

这导致以下不需要的行为:

 ex1 = Example.new('ex1') ex2 = Example.new('ex2') # warning: method redefined; discarding old say_hello ex1.say_hello # => ex2 # Huh?!? 

相反,如果你想要一个单例方法,你需要在单例类中定义它:

 (class << self; self end).send(:define_method, :say_hello) { test } 

这按预期工作:

 ex1 = Example.new('ex1') ex2 = Example.new('ex2') ex1.say_hello # => ex1 ex2.say_hello # => ex2 

在Ruby 1.9中,有一个方法是这样的:

 define_singleton_method(:say_hello) { test } 

现在,按照您想要的方式工作,但是这里存在更高级的问题:这不是Ruby代码。 这是Ruby 语法 ,但它不是Ruby代码,它是Scheme。

现在,Scheme是一门很棒的语言,用Ruby语法编写Scheme代码当然不是一件坏事。 它用Ruby语法编写Java或PHP代码,或者像昨天的一个StackOverflow问题,Ruby语法中的Fortran-57代码那样。 但是这不如用Ruby语法编写Ruby代码。

Scheme是一种function性语言。 函数式语言使用封装和状态的函数(更确切地说是函数闭包)。 但Ruby不是一种function语言,它是一种面向对象的语言,面向对象的语言使用对象进行封装和状态。

所以,函数闭包变成了对象,捕获的variables变成了实例variables。

我们也可以从完全不同的angular度来看待这个问题:你在做的是你正在定义一个单例方法,这个方法的目的是定义一个对象所特有的行为。 但是你为类的每个实例定义了这个单例方法,并且为每个类的实例定义了同一个单例方法。 我们已经有了一个为类的每个实例定义行为的机制:实例方法。

这两个论点都来自完全相反的方向,但他们到达相同的目的地:

 class Example def initialize(test='hey') @test = test end def say_hello @test end end 

我知道这是两年前问的,但我想补充一个答案。 .instance_eval将有助于将方法添加到实例对象

  string = "String" string.instance_eval do def new_method self.reverse end end