【问题标题】:Ruby add method to a classRuby 将方法添加到类
【发布时间】:2016-04-04 09:01:58
【问题描述】:

假设我有一堂课:

class Foo
end

要向此类添加方法,我知道 2 个选项:

  1. 重新打开类并实现方法:

    class Foo
      def bar
      end
    end
    
  2. 使用class_eval实现方法:

    Foo.class_eval { def bar; end}
    

有什么区别?哪个更好?

【问题讨论】:

标签: ruby class methods


【解决方案1】:

实际上,还有其他几种方法可以为类添加新方法。例如,你也可以在模块中定义方法,并将模块混入到原来的类中。

module ExtraMethods
  def bar
  end
end

Foo.class_eval { include ExtraMethods }
class Foo
  include ExtraMethods
end

没有真正的好坏之分。您提到的两种(或三种)方式具有不同的行为,您可能希望根据需要(或偏好)使用一种或另一种。在大多数情况下,这是主观的。在其他情况下,这实际上取决于您的代码的结构。

重新打开类与使用class_eval 的主要客观区别在于,第一个也是类定义,而第二个需要已经定义了原始类。

实际上,在某些情况下重新打开课程可能会导致一些意想不到的副作用。假设您在文件lib/foo.rb 中定义了Foo,并带有一堆方法。然后在config/initializers/extra.rb 中重新打开Foo 并添加bar 方法。

myclass.rb 中,您使用Foo,但不是手动要求lib/foo.rb,而是依靠自动加载功能。

如果extra.rblib/foo.rb 之前加载,可能会发生Foo 类已在您的环境中定义,并且您的代码将不会加载lib/foo.rb。您将拥有一个 Foo 类,其中仅包含您定义的 bar 扩展,而不是原始的 Foo 扩展。

换句话说,如果您出于某种原因重新打开类以添加一些方法而没有确保首先(或之后)加载完整的 origina 类定义,如果依赖于自动加载,您的代码可能会中断。

相反,Foo.class_eval 调用Foo 上的方法,因此它希望在您尝试添加新方法时原始Foo 定义已经存在。这确保了当您添加新方法时,Foo 类已经被定义。

总之,主要区别在于重新打开类允许您(无论好坏)向可能尚未加载的类添加方法,而 class_eval 要求已定义类。

一般来说,除非我定义命名空间子类或重新打开我可以完全控制的类,否则我更喜欢第二种方法,因为在大型代码库中它使代码更易于维护。事实上,如果我扩展第三方类,我通常会使用 mixins,以便在需要覆盖现有方法时保留完整的方法祖先链。

【讨论】:

  • 没有“Ruby 自动加载”,您的意思可能是“Rails 自动加载”。
  • @mudasobwa 技术上存在(autoload 方法),但不适用于这种情况。我对答案做了一个小改动。感谢您指出。
【解决方案2】:

当您需要一些动态的东西时,第二种方法非常方便。 Ruby 实际上有几个作用域:

# scope one, opened with `class` keyword
class ...
  # scope two, opened with `def` keyword
  def ...
  end
end

使用class_eval,您可以共享范围。

>> foo = 1
=> 1
>> class Foo
>>   puts foo
>>   def bar
>>     puts foo
>>   end
>> end
NameError: undefined local variable or method 'foo' for Foo:Class
        from (irb):3:in <class:Foo>
        from (irb):2
>> Foo
=> Foo
>> Foo.class_eval {
?>   puts foo
>>   define_method :bar do
>>     puts foo
>>   end
>> }
1
=> :bar
>> Foo.new.bar
1

【讨论】:

  • 但这也意味着这个共享作用域在类存在时不会被垃圾回收
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-09-13
  • 2011-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-23
  • 2013-09-21
相关资源
最近更新 更多