ruby-将方法添加到实例obj

obj = SomeObject.new

def obj.new_method
  "do some things"
end

puts obj.new_method
> "do some things"

这样可以。 但是,我需要在现有方法中做同样的事情:

def some_random_method
  def obj.new_method
    "do some things"
  end
end

也可以正常工作,但是在方法内部有一个方法看起来非常可怕。 问题是,是否有其他替代方法添加这种方法?

vise asked 2019-11-17T15:53:29Z
7个解决方案
78 votes

我问了这已经很久了。 在ruby 1.9+中,有一种更好的方法是使用define_singleton_method,如下所示:

obj = SomeObject.new

obj.define_singleton_method(:new_method) do
  "do some things"
end
vise answered 2019-11-17T15:53:53Z
51 votes

使用Mixin。

module AdditionalMethods
  def new_method
    "do some things"
  end
end

obj = SomeObject.new
obj.extend(AdditionalMethods)

puts obj.new_method
> "do some things"
Rinzi answered 2019-11-17T15:54:19Z
8 votes

请注意一个有趣的点:

如果您改为:

def my_method
    def my_other_method; end
end

然后,尽管my_other_method的接收者是一个实例,但实际上将在对象的CLASS上定义my_other_method

但是,如果您去(像以前那样):

def my_method
    def self.my_other_method; end
end

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

与您的问题没有直接关系,但仍然很有趣;)

horseyguy answered 2019-11-17T15:55:25Z
6 votes

您可以使用模块。

module ObjSingletonMethods
  def new_method
    "do some things"
  end
end


obj.extend ObjSingletonMethods

puts obj.new_method # => do some things

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

Chirantan answered 2019-11-17T15:56:09Z
5 votes

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

  1. 您可以使用obj = Object.new def obj.my_new_method ... end 成语打开单例类定义:

    obj = Object.new
    def obj.my_new_method
         ...
    end
    
  2. 或者您可以在obj上使用obj = Object.new def obj.my_new_method ... end

    obj = Object.new
    def obj.my_new_method
         ...
    end
    
  3. 您还可以使用单例类中的obj = Object.new def obj.my_new_method ... end

    obj = Object.new
    def obj.my_new_method
         ...
    end
    
  4. 或者,您可以直接使用obj = Object.new def obj.my_new_method ... end

    obj = Object.new
    def obj.my_new_method
         ...
    end
    

注意示例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

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

    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)
David Rissato Cruz answered 2019-11-17T15:57:41Z
1 votes

使用instance_eval

obj = SomeObject.new

obj.instance_eval do
  def new_method
    puts 'do something new'
  end
end

obj.new_method 
> "do something new"
EJ2015 answered 2019-11-17T15:58:08Z
1 votes
class Some
end 

obj = Some.new

class << obj
  def hello 
    puts 'hello'
  end 
end 

obj.hello

obj2 = Some.new
obj2.hello # error

语法self意味着我们正在打开一个对象的类的定义。 您可能知道,我们可以使用如下语法定义Ruby类方法:

class Math

    class << self 

        def cos(x)
            ...
        end 

        def sin(x)
            ...
        end 
    end 
end 

然后,我们可以使用如下方法:

Math.cos(1)

在Ruby中,所有东西都是对象-甚至是类。 self这里是Math class本身的对象(您可以使用Math.class访问该对象)。 因此语法class << self意味着我们要为Math class object打开类。是的,这意味着Math class也具有类(Math.class.class)。

kajamite answered 2019-11-17T15:58:54Z
translate from https://stackoverflow.com:/questions/1887845/add-method-to-an-instanced-object