如何在 Ruby 中实现枚举?

发布于 2024-11-27 10:11:45 字数 64 浏览 4 评论 0原文

在 Ruby 中实现枚举习惯用法的最佳方法是什么?我正在寻找一些我可以使用(几乎)像 Java/C# 枚举的东西。

What's the best way to implement the enum idiom in Ruby? I'm looking for something which I can use (almost) like the Java/C# enums.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(28

各自安好 2024-12-04 10:11:46

另一种方法是使用包含名称和值的哈希的 Ruby 类,如下所示 RubyFleebie博客文章。这使您可以轻松地在值和常量之间进行转换(特别是如果您添加类方法来查找给定值的名称)。

Another approach is to use a Ruby class with a hash containing names and values as described in the following RubyFleebie blog post. This allows you to convert easily between values and constants (especially if you add a class method to lookup the name for a given value).

负佳期 2024-12-04 10:11:46

我认为实现类似枚举类型的最佳方法是使用符号,因为它们几乎表现为整数(当涉及到性能时,object_id 用于进行比较);你不需要担心索引,它们在你的代码中看起来非常整洁 xD

I think the best way to implement enumeration like types is with symbols since the pretty much behave as integer (when it comes to performace, object_id is used to make comparisons ); you don't need to worry about indexing and they look really neat in your code xD

隔岸观火 2024-12-04 10:11:46
irb(main):016:0> num=[1,2,3,4]
irb(main):017:0> alph=['a','b','c','d']
irb(main):018:0> l_enum=alph.to_enum
irb(main):019:0> s_enum=num.to_enum
irb(main):020:0> loop do
irb(main):021:1* puts "#{s_enum.next} - #{l_enum.next}"
irb(main):022:1> end

输出:

1 - a
2 - b
3 - c
4天

irb(main):016:0> num=[1,2,3,4]
irb(main):017:0> alph=['a','b','c','d']
irb(main):018:0> l_enum=alph.to_enum
irb(main):019:0> s_enum=num.to_enum
irb(main):020:0> loop do
irb(main):021:1* puts "#{s_enum.next} - #{l_enum.next}"
irb(main):022:1> end

Output:

1 - a
2 - b
3 - c
4 - d

甜味超标? 2024-12-04 10:11:46

另一种模仿枚举的方法,具有一致的相等处理(无耻地采用戴夫托马斯)。允许开放枚举(很像符号)和封闭(预定义)枚举。

class Enum
  def self.new(values = nil)
    enum = Class.new do
      unless values
        def self.const_missing(name)
          const_set(name, new(name))
        end
      end

      def initialize(name)
        @enum_name = name
      end

      def to_s
        "#{self.class}::#@enum_name"
      end
    end

    if values
      enum.instance_eval do
        values.each { |e| const_set(e, enum.new(e)) }
      end
    end

    enum
  end
end

Genre = Enum.new %w(Gothic Metal) # creates closed enum
Architecture = Enum.new           # creates open enum

Genre::Gothic == Genre::Gothic        # => true
Genre::Gothic != Architecture::Gothic # => true

Another way to mimic an enum with consistent equality handling (shamelessly adopted from Dave Thomas). Allows open enums (much like symbols) and closed (predefined) enums.

class Enum
  def self.new(values = nil)
    enum = Class.new do
      unless values
        def self.const_missing(name)
          const_set(name, new(name))
        end
      end

      def initialize(name)
        @enum_name = name
      end

      def to_s
        "#{self.class}::#@enum_name"
      end
    end

    if values
      enum.instance_eval do
        values.each { |e| const_set(e, enum.new(e)) }
      end
    end

    enum
  end
end

Genre = Enum.new %w(Gothic Metal) # creates closed enum
Architecture = Enum.new           # creates open enum

Genre::Gothic == Genre::Gothic        # => true
Genre::Gothic != Architecture::Gothic # => true
穿透光 2024-12-04 10:11:46

如果您确实想使用点表示法来调用枚举(例如您想使用相同的 Javascript 枚举来 grep 共享代码库),并且您希望 IDE 自动完成,则可以使用 Struct:

ColorStruct = Data.define(:Red, :Blue, :Green)
Colors = ColorStruct.new('red', 'blue', 'green')
blue = Colors.Blue

If you really want to use dot notation to call the enums(say for example you want to grep a shared codebase with identical Javascript enums), and you want your IDE to autocomplete, you can use a Struct:

ColorStruct = Data.define(:Red, :Blue, :Green)
Colors = ColorStruct.new('red', 'blue', 'green')
blue = Colors.Blue
猫瑾少女 2024-12-04 10:11:46

有时我们希望避免创建额外的复杂性并添加新的依赖项,即使它很小。

这个简单的方法对我有用:

class Theme
  RED = 'red'
  GREEN = 'green'
  COLORS = {
    RED => RED,
    GREEN => GREEN,
  }.freeze
end

Theme::COLORS # {"red"=>"red", "green"=>"green"}
Theme::RED # 'red'
Theme::COLORS[Theme::RED] # 'red'
Theme::COLORS['red'] # 'red'
Theme::COLORS['purple'] # nil
Theme::COLORS['purple'] = 'purple' # raises FrozenError!

Sometimes we want to avoid creating extra complexity and adding new dependencies even if small.

This simple one works for me:

class Theme
  RED = 'red'
  GREEN = 'green'
  COLORS = {
    RED => RED,
    GREEN => GREEN,
  }.freeze
end

Theme::COLORS # {"red"=>"red", "green"=>"green"}
Theme::RED # 'red'
Theme::COLORS[Theme::RED] # 'red'
Theme::COLORS['red'] # 'red'
Theme::COLORS['purple'] # nil
Theme::COLORS['purple'] = 'purple' # raises FrozenError!
画骨成沙 2024-12-04 10:11:46

这是迄今为止我找到的最好的解决方案。非常具有可读性,如果您需要的不止于此,那么您不应该使用 enum 的哈哈

MY_ENUM = {
  V1: :V1,
  V2: [1, 2, 3]
}

# > MY_ENUM[:V1]
# => :V1

# > MY_ENUM[:V2]
# => [1, 2, 3]

this is by far the best solution i have found so far. very readable and if you need more than this than you're not supposed to be using enum's lol

MY_ENUM = {
  V1: :V1,
  V2: [1, 2, 3]
}

# > MY_ENUM[:V1]
# => :V1

# > MY_ENUM[:V2]
# => [1, 2, 3]
最冷一天 2024-12-04 10:11:45

两种方式。符号(:foo 表示法)或常量(FOO 表示法)。

当您想要增强可读性而不用文字字符串乱扔代码时,符号是合适的。

postal_code[:minnesota] = "MN"
postal_code[:new_york] = "NY"

当您具有重要的潜在值时,常量是合适的。只需声明一个模块来保存常量,然后在其中声明常量。

module Foo
  BAR = 1
  BAZ = 2
  BIZ = 4
end
 
flags = Foo::BAR | Foo::BAZ # flags = 3

添加了 2021-01-17

如果您要传递枚举值(例如,将其存储在数据库中)并且需要能够将该值转换回符号,则可以混合使用两种方法

COMMODITY_TYPE = {
  currency: 1,
  investment: 2,
}

def commodity_type_string(value)
  COMMODITY_TYPE.key(value)
end

COMMODITY_TYPE[:currency]

这种方法的灵感来自 andrew -grimm的回答https://stackoverflow.com/a/5332950/13468

我还建议阅读此处的其余答案,因为那里有很多方法可以解决这个问题,这实际上可以归结为您关心的其他语言的枚举是什么

Two ways. Symbols (:foo notation) or constants (FOO notation).

Symbols are appropriate when you want to enhance readability without littering code with literal strings.

postal_code[:minnesota] = "MN"
postal_code[:new_york] = "NY"

Constants are appropriate when you have an underlying value that is important. Just declare a module to hold your constants and then declare the constants within that.

module Foo
  BAR = 1
  BAZ = 2
  BIZ = 4
end
 
flags = Foo::BAR | Foo::BAZ # flags = 3

Added 2021-01-17

If you are passing the enum value around (for example, storing it in a database) and you need to be able to translate the value back into the symbol, there's a mashup of both approaches

COMMODITY_TYPE = {
  currency: 1,
  investment: 2,
}

def commodity_type_string(value)
  COMMODITY_TYPE.key(value)
end

COMMODITY_TYPE[:currency]

This approach inspired by andrew-grimm's answer https://stackoverflow.com/a/5332950/13468

I'd also recommend reading through the rest of the answers here since there are a lot of ways to solve this and it really boils down to what it is about the other language's enum that you care about

蓝礼 2024-12-04 10:11:45

我很惊讶没有人提供类似以下内容的内容(摘自 RAPI gem):

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

可以像这样使用:

class FileAttributes < Enum
  enum_attr :readonly,       0x0001
  enum_attr :hidden,         0x0002
  enum_attr :system,         0x0004
  enum_attr :directory,      0x0010
  enum_attr :archive,        0x0020
  enum_attr :in_rom,         0x0040
  enum_attr :normal,         0x0080
  enum_attr :temporary,      0x0100
  enum_attr :sparse,         0x0200
  enum_attr :reparse_point,  0x0400
  enum_attr :compressed,     0x0800
  enum_attr :rom_module,     0x2000
end

示例:

>> example = FileAttributes.new(3)
=> #<FileAttributes:0x629d90 @attrs=3>
>> example.readonly?
=> true
>> example.hidden?
=> true
>> example.system?
=> false
>> example.system = true
=> true
>> example.system?
=> true
>> example.to_i
=> 7

这在数据库场景中,或者在处理 C 风格常量/枚举时效果很好(就像使用 FFI,RAPI 广泛使用)。

此外,您不必担心打字错误会导致静默失败,就像使用哈希类型解决方案一样。

I'm surprised that no one has offered something like the following (harvested from the RAPI gem):

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

Which can be used like so:

class FileAttributes < Enum
  enum_attr :readonly,       0x0001
  enum_attr :hidden,         0x0002
  enum_attr :system,         0x0004
  enum_attr :directory,      0x0010
  enum_attr :archive,        0x0020
  enum_attr :in_rom,         0x0040
  enum_attr :normal,         0x0080
  enum_attr :temporary,      0x0100
  enum_attr :sparse,         0x0200
  enum_attr :reparse_point,  0x0400
  enum_attr :compressed,     0x0800
  enum_attr :rom_module,     0x2000
end

Example:

>> example = FileAttributes.new(3)
=> #<FileAttributes:0x629d90 @attrs=3>
>> example.readonly?
=> true
>> example.hidden?
=> true
>> example.system?
=> false
>> example.system = true
=> true
>> example.system?
=> true
>> example.to_i
=> 7

This plays well in database scenarios, or when dealing with C style constants/enums (as is the case when using FFI, which RAPI makes extensive use of).

Also, you don't have to worry about typos causing silent failures, as you would with using a hash-type solution.

冷情妓 2024-12-04 10:11:45

我使用以下方法:

class MyClass
  MY_ENUM = [MY_VALUE_1 = 'value1', MY_VALUE_2 = 'value2']
end

我喜欢它,因为它具有以下优点:

  1. 它将值直观地分组为一个整体
  2. 它执行一些编译时检查(与仅使用符号相反)
  3. 我可以轻松访问所有可能值的列表:只需 MY_ENUM
  4. 我可以轻松访问不同的值:MY_VALUE_1
  5. 它可以具有任何类型的值,而不仅仅是符号

符号可能更好,因为您不必编写外部类的名称,如果您在其他课程中使用它(MyClass::MY_VALUE_1)

I use the following approach:

class MyClass
  MY_ENUM = [MY_VALUE_1 = 'value1', MY_VALUE_2 = 'value2']
end

I like it for the following advantages:

  1. It groups values visually as one whole
  2. It does some compilation-time checking (in contrast with just using symbols)
  3. I can easily access the list of all possible values: just MY_ENUM
  4. I can easily access distinct values: MY_VALUE_1
  5. It can have values of any type, not just Symbol

Symbols may be better cause you don't have to write the name of outer class, if you are using it in another class (MyClass::MY_VALUE_1)

☆獨立☆ 2024-12-04 10:11:45

最惯用的方法是使用符号。例如,

enum {
  FOO,
  BAR,
  BAZ
}

myFunc(FOO);

您可以只使用符号来代替: ...

# You don't actually need to declare these, of course--this is
# just to show you what symbols look like.
:foo
:bar
:baz

my_func(:foo)

这比枚举更开放,但它非常符合 Ruby 精神。

符号也表现得很好。例如,比较两个符号是否相等比比较两个字符串要快得多。

The most idiomatic way to do this is to use symbols. For example, instead of:

enum {
  FOO,
  BAR,
  BAZ
}

myFunc(FOO);

...you can just use symbols:

# You don't actually need to declare these, of course--this is
# just to show you what symbols look like.
:foo
:bar
:baz

my_func(:foo)

This is a bit more open-ended than enums, but it fits well with the Ruby spirit.

Symbols also perform very well. Comparing two symbols for equality, for example, is much faster than comparing two strings.

梦中楼上月下 2024-12-04 10:11:45

如果您使用 Rails 4.2 或更高版本,则可以使用 Rails 枚举。

Rails 现在默认具有枚举,无需包含任何 gem。

这与 Java、C++ 枚举非常相似(并且具有更多功能)。

引用自 http://edgeapi.rubyonrails.org/classes/ActiveRecord/Enum.html:

class Conversation < ActiveRecord::Base
  enum status: [ :active, :archived ]
end

# conversation.update! status: 0
conversation.active!
conversation.active? # => true
conversation.status  # => "active"

# conversation.update! status: 1
conversation.archived!
conversation.archived? # => true
conversation.status    # => "archived"

# conversation.update! status: 1
conversation.status = "archived"

# conversation.update! status: nil
conversation.status = nil
conversation.status.nil? # => true
conversation.status      # => nil

If you are using Rails 4.2 or greater you can use Rails enums.

Rails now has enums by default without the need for including any gems.

This is very similar (and more with features) to Java, C++ enums.

Quoted from http://edgeapi.rubyonrails.org/classes/ActiveRecord/Enum.html :

class Conversation < ActiveRecord::Base
  enum status: [ :active, :archived ]
end

# conversation.update! status: 0
conversation.active!
conversation.active? # => true
conversation.status  # => "active"

# conversation.update! status: 1
conversation.archived!
conversation.archived? # => true
conversation.status    # => "archived"

# conversation.update! status: 1
conversation.status = "archived"

# conversation.update! status: nil
conversation.status = nil
conversation.status.nil? # => true
conversation.status      # => nil
写下不归期 2024-12-04 10:11:45

查看 ruby​​-enum gem,https://github.com/dblock/ruby-enum

class Gender
  include Enum

  Gender.define :MALE, "male"
  Gender.define :FEMALE, "female"
end

Gender.all
Gender::MALE

Check out the ruby-enum gem, https://github.com/dblock/ruby-enum.

class Gender
  include Enum

  Gender.define :MALE, "male"
  Gender.define :FEMALE, "female"
end

Gender.all
Gender::MALE
握住我的手 2024-12-04 10:11:45

我知道这个人已经很久没有发布这个问题了,但我也有同样的问题,而这篇文章没有给我答案。我想要一种简单的方法来查看数字代表什么,进行简单的比较,最重要的是 ActiveRecord 支持使用代表枚举的列进行查找。

我没有找到任何东西,所以我做了一个名为 yinum 的很棒的实现,它允许我寻找的一切。做了很多规格,所以我很确定它是安全的。

一些示例功能:

COLORS = Enum.new(:COLORS, :red => 1, :green => 2, :blue => 3)
=> COLORS(:red => 1, :green => 2, :blue => 3)
COLORS.red == 1 && COLORS.red == :red
=> true

class Car < ActiveRecord::Base    
  attr_enum :color, :COLORS, :red => 1, :black => 2
end
car = Car.new
car.color = :red / "red" / 1 / "1"
car.color
=> Car::COLORS.red
car.color.black?
=> false
Car.red.to_sql
=> "SELECT `cars`.* FROM `cars` WHERE `cars`.`color` = 1"
Car.last.red?
=> true

I know it's been a long time since the guy posted this question, but I had the same question and this post didn't give me the answer. I wanted an easy way to see what the number represents, easy comparison, and most of all ActiveRecord support for lookup using the column representing the enum.

I didn't find anything, so I made an awesome implementation called yinum which allowed everything I was looking for. Made ton of specs, so I'm pretty sure it's safe.

Some example features:

COLORS = Enum.new(:COLORS, :red => 1, :green => 2, :blue => 3)
=> COLORS(:red => 1, :green => 2, :blue => 3)
COLORS.red == 1 && COLORS.red == :red
=> true

class Car < ActiveRecord::Base    
  attr_enum :color, :COLORS, :red => 1, :black => 2
end
car = Car.new
car.color = :red / "red" / 1 / "1"
car.color
=> Car::COLORS.red
car.color.black?
=> false
Car.red.to_sql
=> "SELECT `cars`.* FROM `cars` WHERE `cars`.`color` = 1"
Car.last.red?
=> true
海风掠过北极光 2024-12-04 10:11:45

这是我在 Ruby 中使用枚举的方法。我想要的是简短而甜蜜的,不一定是最像 C 的。有什么想法吗?

module Kernel
  def enum(values)
    Module.new do |mod|
      values.each_with_index{ |v,i| mod.const_set(v.to_s.capitalize, 2**i) }

      def mod.inspect
        "#{self.name} {#{self.constants.join(', ')}}"
      end
    end
  end
end

States = enum %w(Draft Published Trashed)
=> States {Draft, Published, Trashed} 

States::Draft
=> 1

States::Published
=> 2

States::Trashed
=> 4

States::Draft | States::Trashed
=> 5

This is my approach to enums in Ruby. I was going for short and sweet, not necessarily the the most C-like. Any thoughts?

module Kernel
  def enum(values)
    Module.new do |mod|
      values.each_with_index{ |v,i| mod.const_set(v.to_s.capitalize, 2**i) }

      def mod.inspect
        "#{self.name} {#{self.constants.join(', ')}}"
      end
    end
  end
end

States = enum %w(Draft Published Trashed)
=> States {Draft, Published, Trashed} 

States::Draft
=> 1

States::Published
=> 2

States::Trashed
=> 4

States::Draft | States::Trashed
=> 5
各自安好 2024-12-04 10:11:45

也许最好的轻量级方法是这样

module MyConstants
  ABC = Class.new
  DEF = Class.new
  GHI = Class.new
end

,值具有关联的名称,如在 Java/C# 中:

MyConstants::ABC
=> MyConstants::ABC

要获取所有值,您可以这样做

MyConstants.constants
=> [:ABC, :DEF, :GHI] 

如果您想要枚举的序数值,您可以这样做

MyConstants.constants.index :GHI
=> 2

Perhaps the best lightweight approach would be

module MyConstants
  ABC = Class.new
  DEF = Class.new
  GHI = Class.new
end

This way values have associated names, as in Java/C#:

MyConstants::ABC
=> MyConstants::ABC

To get all values, you can do

MyConstants.constants
=> [:ABC, :DEF, :GHI] 

If you want an enum's ordinal value, you can do

MyConstants.constants.index :GHI
=> 2
输什么也不输骨气 2024-12-04 10:11:45

如果您担心符号拼写错误,请确保您的代码在使用不存在的键访问值时引发异常。您可以通过使用 fetch 而不是 [] 来完成此操作:

my_value = my_hash.fetch(:key)

或者如果您提供不存在的密钥,则默认情况下使散列引发异常:

my_hash = Hash.new do |hash, key|
  raise "You tried to access using #{key.inspect} when the only keys we have are #{hash.keys.inspect}"
end

如果散列已存在,您可以添加异常引发行为:

my_hash = Hash[[[1,2]]]
my_hash.default_proc = proc do |hash, key|
  raise "You tried to access using #{key.inspect} when the only keys we have are #{hash.keys.inspect}"
end

通常,您不必担心常量的拼写错误安全性。如果常量名称拼写错误,通常会引发异常。

If you're worried about typos with symbols, make sure your code raises an exception when you access a value with a non-existent key. You can do this by using fetch rather than []:

my_value = my_hash.fetch(:key)

or by making the hash raise an exception by default if you supply a non-existent key:

my_hash = Hash.new do |hash, key|
  raise "You tried to access using #{key.inspect} when the only keys we have are #{hash.keys.inspect}"
end

If the hash already exists, you can add on exception-raising behaviour:

my_hash = Hash[[[1,2]]]
my_hash.default_proc = proc do |hash, key|
  raise "You tried to access using #{key.inspect} when the only keys we have are #{hash.keys.inspect}"
end

Normally, you don't have to worry about typo safety with constants. If you misspell a constant name, it'll usually raise an exception.

伴我老 2024-12-04 10:11:45

另一种解决方案是使用 OpenStruct。它非常直接和干净。

https://ruby-doc.org/stdlib-2.3 .1/libdoc/ostruct/rdoc/OpenStruct.html

示例:

# bar.rb
require 'ostruct' # not needed when using Rails

# by patching Array you have a simple way of creating a ENUM-style
class Array
   def to_enum(base=0)
      OpenStruct.new(map.with_index(base).to_h)
   end
end

class Bar

    MY_ENUM = OpenStruct.new(ONE: 1, TWO: 2, THREE: 3)
    MY_ENUM2 = %w[ONE TWO THREE].to_enum

    def use_enum (value)
        case value
        when MY_ENUM.ONE
            puts "Hello, this is ENUM 1"
        when MY_ENUM.TWO
            puts "Hello, this is ENUM 2"
        when MY_ENUM.THREE
            puts "Hello, this is ENUM 3"
        else
            puts "#{value} not found in ENUM"
        end
    end

end

# usage
foo = Bar.new    
foo.use_enum 1
foo.use_enum 2
foo.use_enum 9


# put this code in a file 'bar.rb', start IRB and type: load 'bar.rb'

Another solution is using OpenStruct. Its pretty straight forward and clean.

https://ruby-doc.org/stdlib-2.3.1/libdoc/ostruct/rdoc/OpenStruct.html

Example:

# bar.rb
require 'ostruct' # not needed when using Rails

# by patching Array you have a simple way of creating a ENUM-style
class Array
   def to_enum(base=0)
      OpenStruct.new(map.with_index(base).to_h)
   end
end

class Bar

    MY_ENUM = OpenStruct.new(ONE: 1, TWO: 2, THREE: 3)
    MY_ENUM2 = %w[ONE TWO THREE].to_enum

    def use_enum (value)
        case value
        when MY_ENUM.ONE
            puts "Hello, this is ENUM 1"
        when MY_ENUM.TWO
            puts "Hello, this is ENUM 2"
        when MY_ENUM.THREE
            puts "Hello, this is ENUM 3"
        else
            puts "#{value} not found in ENUM"
        end
    end

end

# usage
foo = Bar.new    
foo.use_enum 1
foo.use_enum 2
foo.use_enum 9


# put this code in a file 'bar.rb', start IRB and type: load 'bar.rb'
等待我真够勒 2024-12-04 10:11:45

这完全取决于您如何使用 Java 或 C# 枚举。您如何使用它将决定您在 Ruby 中选择的解决方案。

尝试使用原生 Set 类型,例如:

>> enum = Set['a', 'b', 'c']
=> #<Set: {"a", "b", "c"}>
>> enum.member? "b"
=> true
>> enum.member? "d"
=> false
>> enum.add? "b"
=> nil
>> enum.add? "d"
=> #<Set: {"a", "b", "c", "d"}>

It all depends how you use Java or C# enums. How you use it will dictate the solution you'll choose in Ruby.

Try the native Set type, for instance:

>> enum = Set['a', 'b', 'c']
=> #<Set: {"a", "b", "c"}>
>> enum.member? "b"
=> true
>> enum.member? "d"
=> false
>> enum.add? "b"
=> nil
>> enum.add? "d"
=> #<Set: {"a", "b", "c", "d"}>
冰雪梦之恋 2024-12-04 10:11:45

有人继续编写了一个名为 Renum 的 ruby​​ gem。它声称可以获得最接近 Java/C# 的行为。就我个人而言,我仍在学习 Ruby,当我想让一个特定的类包含一个静态枚举(可能是一个散列)时,我有点震惊,因为通过谷歌很难找到它。

Someone went ahead and wrote a ruby gem called Renum. It claims to get the closest Java/C# like behavior. Personally I'm still learning Ruby, and I was a little shocked when I wanted to make a specific class contain a static enum, possibly a hash, that it wasn't exactly easily found via google.

无尽的现实 2024-12-04 10:11:45

最近,我们发布了一个gem,它实现了Ruby 中的枚举。在我的帖子中,您会找到问题的答案。我还描述了为什么我们的实现比现有的更好(实际上 Ruby 中有许多此功能的实现,但作为 gems)。

Recently we released a gem that implements Enums in Ruby. In my post you will find the answers on your questions. Also I described there why our implementation is better than existing ones (actually there are many implementations of this feature in Ruby yet as gems).

遇到 2024-12-04 10:11:45

符号是 ruby​​ 的方式。然而,有时需要与一些 C 代码或某些东西或 Java 进行交互,这些代码公开了一些用于各种事物的枚举。


#server_roles.rb
module EnumLike

  def EnumLike.server_role
    server_Symb=[ :SERVER_CLOUD, :SERVER_DESKTOP, :SERVER_WORKSTATION]
    server_Enum=Hash.new
    i=0
    server_Symb.each{ |e| server_Enum[e]=i; i +=1}
    return server_Symb,server_Enum
  end

end

然后可以像这样使用


require 'server_roles'

sSymb, sEnum =EnumLike.server_role()

foreignvec[sEnum[:SERVER_WORKSTATION]]=8

这当然可以变得抽象,你可以推出我们自己的 Enum 类

Symbols is the ruby way. However, sometimes one need to talk to some C code or something or Java that expose some enum for various things.


#server_roles.rb
module EnumLike

  def EnumLike.server_role
    server_Symb=[ :SERVER_CLOUD, :SERVER_DESKTOP, :SERVER_WORKSTATION]
    server_Enum=Hash.new
    i=0
    server_Symb.each{ |e| server_Enum[e]=i; i +=1}
    return server_Symb,server_Enum
  end

end

This can then be used like this


require 'server_roles'

sSymb, sEnum =EnumLike.server_role()

foreignvec[sEnum[:SERVER_WORKSTATION]]=8

This is can of course be made abstract and you can roll our own Enum class

故事灯 2024-12-04 10:11:45

我已经实现了这样的枚举

module EnumType

  def self.find_by_id id
    if id.instance_of? String
      id = id.to_i
    end 
    values.each do |type|
      if id == type.id
        return type
      end
    end
    nil
  end

  def self.values
    [@ENUM_1, @ENUM_2] 
  end

  class Enum
    attr_reader :id, :label

    def initialize id, label
      @id = id
      @label = label
    end
  end

  @ENUM_1 = Enum.new(1, "first")
  @ENUM_2 = Enum.new(2, "second")

end

那么很容易进行操作

EnumType.ENUM_1.label

......

enum = EnumType.find_by_id 1

valueArray = EnumType.values

I have implemented enums like that

module EnumType

  def self.find_by_id id
    if id.instance_of? String
      id = id.to_i
    end 
    values.each do |type|
      if id == type.id
        return type
      end
    end
    nil
  end

  def self.values
    [@ENUM_1, @ENUM_2] 
  end

  class Enum
    attr_reader :id, :label

    def initialize id, label
      @id = id
      @label = label
    end
  end

  @ENUM_1 = Enum.new(1, "first")
  @ENUM_2 = Enum.new(2, "second")

end

then its easy to do operations

EnumType.ENUM_1.label

...

enum = EnumType.find_by_id 1

...

valueArray = EnumType.values
生生漫 2024-12-04 10:11:45
module Status
  BAD  = 13
  GOOD = 24

  def self.to_str(status)
    for sym in self.constants
      if self.const_get(sym) == status
        return sym.to_s
      end
    end
  end

end


mystatus = Status::GOOD

puts Status::to_str(mystatus)

输出:

GOOD
module Status
  BAD  = 13
  GOOD = 24

  def self.to_str(status)
    for sym in self.constants
      if self.const_get(sym) == status
        return sym.to_s
      end
    end
  end

end


mystatus = Status::GOOD

puts Status::to_str(mystatus)

Output:

GOOD
请爱~陌生人 2024-12-04 10:11:45

这看起来有点多余,但这是我使用过几次的方法,特别是在我与 xml 或类似的集成时。

#model
class Profession
  def self.pro_enum
    {:BAKER => 0, 
     :MANAGER => 1, 
     :FIREMAN => 2, 
     :DEV => 3, 
     :VAL => ["BAKER", "MANAGER", "FIREMAN", "DEV"]
    }
  end
end

Profession.pro_enum[:DEV]      #=>3
Profession.pro_enum[:VAL][1]   #=>MANAGER

这给了我 ac# enum 的严格性,并且它与模型相关。

This seems a bit superfluous, but this is a methodology that I have used a few times, especially where I am integrating with xml or some such.

#model
class Profession
  def self.pro_enum
    {:BAKER => 0, 
     :MANAGER => 1, 
     :FIREMAN => 2, 
     :DEV => 3, 
     :VAL => ["BAKER", "MANAGER", "FIREMAN", "DEV"]
    }
  end
end

Profession.pro_enum[:DEV]      #=>3
Profession.pro_enum[:VAL][1]   #=>MANAGER

This gives me the rigor of a c# enum and it is tied to the model.

记忆で 2024-12-04 10:11:45

大多数人使用符号(即 :foo_bar 语法)。它们是一种独特的、不透明的价值观。符号不属于任何枚举类型,因此它们并不是 C 枚举类型的真正忠实表示,但这已经是最好的了。

Most people use symbols (that's the :foo_bar syntax). They're sort of unique opaque values. Symbols don't belong to any enum-style type so they're not really a faithful representation of C's enum type but this is pretty much as good as it gets.

无名指的心愿 2024-12-04 10:11:45

有时我需要的只是能够获取枚举的值并识别其名称,类似于java世界。

module Enum
     def get_value(str)
       const_get(str)
     end
     def get_name(sym)
       sym.to_s.upcase
     end
 end

 class Fruits
   include Enum
   APPLE = "Delicious"
   MANGO = "Sweet"
 end

 Fruits.get_value('APPLE') #'Delicious'
 Fruits.get_value('MANGO') # 'Sweet'

 Fruits.get_name(:apple) # 'APPLE'
 Fruits.get_name(:mango) # 'MANGO'

对我来说,这服务于枚举的目的,并使其具有很强的可扩展性。您可以向 Enum 类添加更多方法,viola 在所有定义的枚举中免费获取它们。例如。 get_all_names 之类的东西。

Sometimes all I need is to be able to fetch enum's value and identify its name similar to java world.

module Enum
     def get_value(str)
       const_get(str)
     end
     def get_name(sym)
       sym.to_s.upcase
     end
 end

 class Fruits
   include Enum
   APPLE = "Delicious"
   MANGO = "Sweet"
 end

 Fruits.get_value('APPLE') #'Delicious'
 Fruits.get_value('MANGO') # 'Sweet'

 Fruits.get_name(:apple) # 'APPLE'
 Fruits.get_name(:mango) # 'MANGO'

This to me serves the purpose of enum and keeps it very extensible too. You can add more methods to the Enum class and viola get them for free in all the defined enums. for example. get_all_names and stuff like that.

寄居人 2024-12-04 10:11:45

尝试一下 inum。
https://github.com/alfa-jpn/inum

class Color < Inum::Base
  define :RED
  define :GREEN
  define :BLUE
end
Color::RED 
Color.parse('blue') # => Color::BLUE
Color.parse(2)      # => Color::GREEN

查看更多https://github.com/alfa-jpn/inum#usage

Try the inum.
https://github.com/alfa-jpn/inum

class Color < Inum::Base
  define :RED
  define :GREEN
  define :BLUE
end
Color::RED 
Color.parse('blue') # => Color::BLUE
Color.parse(2)      # => Color::GREEN

see more https://github.com/alfa-jpn/inum#usage

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文