有没有一种方法可以从该实例内部为一个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示例中的ex1
或ex2
),这意味着self.class
是ex1
的类,即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