将方法添加到实例化对象

vis*_*ise 56 ruby

obj = SomeObject.new

def obj.new_method
  "do some things"
end

puts obj.new_method
> "do some things"
Run Code Online (Sandbox Code Playgroud)

这没问题.但是,我需要在现有方法中做同样的事情:

def some_random_method
  def obj.new_method
    "do some things"
  end
end
Run Code Online (Sandbox Code Playgroud)

也可以正常工作,但在方法中使用方法看起来非常可怕.问题是,有没有其他方法可以添加这样的方法?

vis*_*ise 79

我问这个问题已经很久了.在ruby 1.9+中,有一种更好的方法可以通过使用define_singleton_method,如下所示:

obj = SomeObject.new

obj.define_singleton_method(:new_method) do
  "do some things"
end
Run Code Online (Sandbox Code Playgroud)

  • 如果我在`do`块中使用`@field`会发生什么?我会从当前类访问一个字段,还是会使用`obj`字段? (2认同)

小智 51

使用Mixin.

module AdditionalMethods
  def new_method
    "do some things"
  end
end

obj = SomeObject.new
obj.extend(AdditionalMethods)

puts obj.new_method
> "do some things"
Run Code Online (Sandbox Code Playgroud)


hor*_*guy 8

只是一个有趣的注意事项:

如果你已经离开了:

def my_method
    def my_other_method; end
end
Run Code Online (Sandbox Code Playgroud)

然后my_other_method实际上将在对象的CLASS上定义,而不是接收者my_method是一个实例.

但是如果你去(就像你一样):

def my_method
    def self.my_other_method; end
end
Run Code Online (Sandbox Code Playgroud)

然后my_other_method在实例的本征类上定义.

与你的问题没有直接关系,但有点有趣;)


Chi*_*tan 6

您可以使用模块.

module ObjSingletonMethods
  def new_method
    "do some things"
  end
end


obj.extend ObjSingletonMethods

puts obj.new_method # => do some things
Run Code Online (Sandbox Code Playgroud)

现在,如果您需要向该对象添加更多方法,您只需要在模块中实现这些方法即可.


Dav*_*ruz 6

有几种方法可以实现此目的,它们都与单例类有关:

  1. 您可以使用class <<惯用语打开单例类定义:

    obj = Object.new
    class << obj
      def my_new_method
         ...
      end
    end
    
    Run Code Online (Sandbox Code Playgroud)
  2. 或者您可以define_singleton_method在obj上使用:

    obj = Object.new
    obj.define_sigleton_method(:my_new_method) do
         ...
    end
    
    Run Code Online (Sandbox Code Playgroud)
  3. 您也可以define_method在单例类中使用:

    obj = Object.new
    obj.singleton_class.define_method(:my_new_method) do
         ...
    end
    
    Run Code Online (Sandbox Code Playgroud)
  4. 或者您可以def直接使用:

    obj = Object.new
    def obj.my_new_method
         ...
    end
    
    Run Code Online (Sandbox Code Playgroud)

注意示例3,我认为单例类的概念在该类上更加清晰。这两个示例之间存在差异:

    a = Object.new
    b = Object.new

    # -- defining a new method in the object's "class" --
    a.class.define_method(:abc) do
      puts "hello abc"
    end

    a.abc # prints "hello abc"
    b.abc # also prints "hello abc"

    # -- defining a new method in the object's "singleton class" --
    a.singleton_class.define_method(:bcd) do
      puts "hello bcd"
    end

    a.bcd # prints "hello bcd"
    b.bcd # error undefined method
Run Code Online (Sandbox Code Playgroud)

这是因为每个对象都有其自己的单例类:

    a = Object.new
    b = Object.new

    p a.class # prints "Object"
    p a.singleton_class # prints "#<Class:#<Object:0x000055ebc0b84438>>"

    p b.class # also prints "Object"
    p b.singleton_class # prints "#<Class:#<Object:0x000055ebc0b84410>>" (a different reference address)
Run Code Online (Sandbox Code Playgroud)