373 Stimmen

Wie implementiert man Enums in Ruby?

Was ist der beste Weg, um die enum Idiom in Ruby zu implementieren? Ich bin auf der Suche nach etwas, das ich (fast) wie die Java/C# enums verwenden können.

373voto

mlibby Punkte 6096

Zwei Möglichkeiten. Symbole ( :foo Notation) oder Konstanten ( FOO Notation).

Symbole sind sinnvoll, wenn Sie die Lesbarkeit verbessern wollen, ohne den Code mit literalen Zeichenfolgen zu überfrachten.

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

Konstanten sind geeignet, wenn Sie einen wichtigen Wert haben. Deklarieren Sie einfach ein Modul, das Ihre Konstanten aufnimmt, und deklarieren Sie dann die Konstanten innerhalb dieses Moduls.

module Foo
  BAR = 1
  BAZ = 2
  BIZ = 4
end

flags = Foo::BAR | Foo::BAZ # flags = 3

Addierte 2021-01-17

Wenn Sie den Enum-Wert weitergeben (z. B. in einer Datenbank speichern) und in der Lage sein müssen, den Wert zurück in das Symbol zu übersetzen, gibt es eine Kombination aus beiden Ansätzen

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

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

COMMODITY_TYPE[:currency]

Dieser Ansatz wurde durch die Antwort von andrew-grimm inspiriert https://stackoverflow.com/a/5332950/13468

Ich würde auch empfehlen, durch den Rest der Antworten hier zu lesen, da es viele Möglichkeiten gibt, dieses Problem zu lösen und es wirklich darauf hinausläuft, was es über die andere Sprache Enum ist, die Sie interessieren

63voto

Charles Punkte 6044

Ich bin überrascht, dass niemand etwas wie das Folgende angeboten hat (entnommen aus der 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

Das kann folgendermaßen verwendet werden:

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

Beispiel:

>> 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

Dies funktioniert gut in Datenbankszenarien oder beim Umgang mit Konstanten/Enums im C-Stil (wie es bei der Verwendung von FFI wovon RAPI ausgiebig Gebrauch macht).

Außerdem müssen Sie nicht befürchten, dass Tippfehler zu stillen Fehlern führen, wie es bei der Verwendung einer Hash-Lösung der Fall wäre.

59voto

Alexey Punkte 8727

Ich verwende den folgenden Ansatz:

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

Ich mag es aus folgenden Gründen:

  1. Es gruppiert Werte visuell als ein Ganzes
  2. Es führt einige Überprüfungen während der Kompilierung durch (im Gegensatz zur Verwendung von Symbolen)
  3. Ich kann die Liste aller möglichen Werte leicht abrufen: einfach MY_ENUM
  4. Ich kann leicht auf unterschiedliche Werte zugreifen: MY_VALUE_1
  5. Sie kann Werte beliebigen Typs enthalten, nicht nur Symbol

Symbole können besser sein, weil man den Namen der äußeren Klasse nicht schreiben muss, wenn man sie in einer anderen Klasse verwendet ( MyClass::MY_VALUE_1 )

52voto

emk Punkte 58032

Die idiomatischste Art, dies zu tun, ist die Verwendung von Symbolen. Zum Beispiel, anstatt von:

enum {
  FOO,
  BAR,
  BAZ
}

myFunc(FOO);

...können Sie einfach Symbole verwenden:

# 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)

Dies ist ein wenig offener als enums, aber es passt gut zum Geist von Ruby.

Auch Symbole schneiden sehr gut ab. Der Vergleich von zwei Symbolen auf Gleichheit ist zum Beispiel viel schneller als der Vergleich von zwei Zeichenketten.

19voto

Vedant Agarwala Punkte 16862

Wenn Sie Rails 4.2 oder höher verwenden, können Sie Rails-Enums verwenden.

Rails verfügt nun standardmäßig über Enums, ohne dass irgendwelche Gems eingebunden werden müssen.

Dies ist sehr ähnlich (und mehr mit Funktionen) zu Java, C + + enums.

Zitiert von 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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X