如何在Ruby中使用C#样式枚举?

时间:2020-03-06 15:03:06  来源:igfitidea点击:

我只想知道在Ruby中模拟Cstyle枚举的最佳方法。

解决方案

我不认为Ruby支持真正的枚举-尽管仍然有可用的解决方案。

枚举和Ruby

在ruby中定义枚举的最简单方法是使用带有常量变量的类。

class WindowState
  Open = 1
  Closed = 2
  Max = 3
  Min = 4
end

这不是完全一样,但是我经常会为这种事情构建一个哈希值:

STATES = {:open => 1, :closed => 2, :max => 3, :min => 4}.freeze()

冻结哈希可以防止我意外修改其内容。

此外,如果要在访问不存在的内容时引发错误,则可以使用defualt Proc执行此操作:

STATES = Hash.new { |hash, key| raise NameError, "#{key} is not allowed" }
STATES.merge!({:open => 1, :closed => 2, :max => 3, :min => 4}).freeze()

STATES[:other] # raises NameError

按照其他人的说法进行分类或者散列是可行的。但是,Ruby要做的是使用符号。 Ruby中的符号以冒号开头,如下所示:

greetingtype = :hello

它们有点像只包含名称的对象。

Specifically, I would like to be able to perform logical tests against the set of values given some variable. Example would be the state of a window: "minimized, maximized, closed, open"

如果我们需要枚举来映射到值(例如,我们需要最小化等于0,最大化到等于100,等等),我将使用符号的哈希值将其映射到值,如下所示:

WINDOW_STATES = { :minimized => 0, :maximized => 100 }.freeze

冻结(如nate所说的那样)使我们避免将来意外破碎东西。
我们可以通过执行此操作来检查某项内容是否有效

WINDOW_STATES.keys.include?(window_state)

另外,如果我们不需要任何值,而只需要检查" membership",则可以使用数组

WINDOW_STATES = [:minimized, :maximized].freeze

这样使用

WINDOW_STATES.include?(window_state)

如果键将是字符串(例如RoR应用程序中的" state"字段),则可以使用字符串数组。我一直在我们的许多Rails应用程序中执行此操作。

WINDOW_STATES = %w(minimized maximized open closed).freeze

这几乎是Rails的validates_inclusion_of验证器专门为:-)构建的。

个人说明:

我不喜欢输入包含?一直如此,所以我有这个问题(这只是因为.in?(1、2、3)的情况而变得复杂:

class Object

    # Lets us write array.include?(x) the other way round
    # Also accepts multiple args, so we can do 2.in?( 1,2,3 ) without bothering with arrays
    def in?( *args )
        # if we have 1 arg, and it is a collection, act as if it were passed as a single value, UNLESS we are an array ourselves.
        # The mismatch between checking for respond_to on the args vs checking for self.kind_of?Array is deliberate, otherwise
        # arrays of strings break and ranges don't work right
        args.length == 1 && args.first.respond_to?(:include?) && !self.kind_of?(Array) ?
            args.first.include?( self ) :
            args.include?( self )
        end
    end
end

这使我们可以键入

window_state.in? WINDOW_STATES