【问题标题】:ruby understanding enum methodruby 理解枚举方法
【发布时间】:2012-06-26 06:32:43
【问题描述】:

我正在阅读另一个 SO 问题 Enums in Ruby,它有以下代码 sn-p:

class Enum

  private

  def self.enum_attr(name, num)
    name = name.to_s

    define_method(name + '?') do
      @attrs & num != 0
    end

    define_method(name + '=') do |set|
      if set
        @attrs |= num
      else
        @attrs &= ~num
      end
    end
  end

  public

  def initialize(attrs = 0)
    @attrs = attrs
  end

  def to_i
    @attrs
  end
end

据我了解,这是定义一个名为enum_attr 的类方法,对吗?我不确定的是在 enum_attr 方法中包含 define_method 语句意味着什么。

然后在那篇文章的后面,它显示了类被扩展如下

class FileAttributes < Enum
  enum_attr :readonly,       0x0001
  enum_attr :hidden,         0x0002
end

我不太明白第二部分的作用 - 谁能解释一下?

【问题讨论】:

    标签: ruby metaprogramming


    【解决方案1】:

    Enum 中,方法enum_attr 定义在类的单例上,并且可供所有子类使用。此方法在类定义主体的范围内,在FileAttributes 中,它使用参数:readonly, 0x0001:hidden, 0x0002 调用。

    enum_attr被调用时(让我们看看第一个调用,enum_attr :readonly, 0x0001),它定义了两个方法:readonly?readonly=(set)。调用enum_attr 的结果在功能上等同于在FileAttributes 中写出以下内容:

    def readonly?
      @attrs & 0x0001 != 0
    end
    
    def readonly=(set)
      if set
        @attrs |= 0x0001
      else
        @attrs &= ~0x0001
      end
    end
    

    由于传递给define_method 的块是一个闭包,因此当您调用定义的方法时,传递块的作用域中的变量num 仍然在作用域内。换句话说,传递给enum_attrnum 变量在生成的方法readonly?readonly= 中在稍后从不同的范围调用它们时仍然可用。

    必须使用define_method,因为方法的名称是动态生成的(即我们事先不知道方法的名称)。

    【讨论】:

    • 感谢您的解释。那么 enum_attr :readonly, 0x0001 只是一个带有两个参数的方法调用?如果是这样,该代码是否仅在 FileAttributes 的主体中?它不需要在方法块中或初始化中吗?
    • 如果您有 Java 等背景,您可能会这么认为,但 Ruby 不是这样工作的。您可以在 class 块中运行您喜欢的任何代码。在 class 块内,self 将是正在定义的类,因此任何没有接收器的方法调用都将转到类对象(在本例中为 FileAttributes)。
    • 啊,我明白了,谢谢。如果 FileAttributes 被列为私有,如何实际调用 enum_attr?
    • private 方法永远不能用接收器调用,所以你只能在self 上调用它们。在这种情况下,selfFileAttributes,就像它在对 FileAttributes 上的类方法的调用中一样。
    • @JeffStorey private 在 Ruby 中与 private 不同,是其他一些语言。 Ruby 中的私有方法可以被子类访问。
    【解决方案2】:

    您正在查看一个类方法,该方法生成使用位域存储的真/假属性。你有 C(或者 Java)的背景吗?如果是这样,您可能熟悉位域和一般的“位旋转”。大多数有关这些主题的 Internet 资源都与 C 相关;但您仍然可以在 Ruby 和其他语言中使用它们。

    在这种情况下,将布尔属性存储在单个位中不会有任何好处,我建议您不要实际使用此代码。最好为每个属性使用不同的实例变量,使用 truefalse 值。

    【讨论】:

    • 谢谢。我熟悉投标交易。我实际上并没有尝试使用此代码,但我正在学习 ruby​​,并且我试图理解代码比什么都重要。
    • 好的。您可以从这段代码中获得一些非常重要的概念:Ruby 中的类也是对象,您可以在它们上调用方法; Ruby 中的类和方法定义没有什么“特别”的地方(它们只是像任何其他代码一样执行的代码);另外,如果你不熟悉闭包,这对你来说是一个很好的介绍。要了解 Ruby,您需要“获取”闭包,因此请确保您了解那里发生了什么。
    • 是的,我有 groovy/Java 背景,所以我在 groovy 中经常使用闭包。我发现很多 ruby​​ 中的代码概念很容易理解,因为我做了很多常规工作。
    猜你喜欢
    • 2015-05-28
    • 2016-12-24
    • 2021-02-22
    • 2012-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-02
    • 2020-01-08
    相关资源
    最近更新 更多