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.
Antworten
Zu viele Anzeigen?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
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.
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:
- Es gruppiert Werte visuell als ein Ganzes
- Es führt einige Überprüfungen während der Kompilierung durch (im Gegensatz zur Verwendung von Symbolen)
- Ich kann die Liste aller möglichen Werte leicht abrufen: einfach
MY_ENUM
- Ich kann leicht auf unterschiedliche Werte zugreifen:
MY_VALUE_1
- 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
)
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.
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
- See previous answers
- Weitere Antworten anzeigen