在Ruby中实现枚举习语的最佳方法是什么?我正在寻找一些东西,我可以使用(几乎)像Java/ c#枚举。
当前回答
这完全取决于你如何使用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"}>
其他回答
我实现过这样的枚举
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
有时我所需要的是能够获取enum的值,并识别其名称类似于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可以在所有已定义的Enum中免费获得它们。为例。Get_all_names之类的。
两种方式。符号(: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的启发
我也建议阅读这里剩下的答案,因为有很多方法来解决这个问题,它实际上归结为你关心的其他语言的枚举
最常用的方法是使用符号。例如,不要:
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精神。
符号的表现也很好。例如,比较两个相等的符号要比比较两个字符串快得多。
我很惊讶,没有人提供以下内容(从RAPI宝石中收获):
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广泛使用FFI)。
此外,您不必像使用散列类型解决方案那样,担心拼写错误会导致无声失败。
推荐文章
- 是否可以在MiniTest中运行单个测试?
- 如何在Ruby中生成a和b之间的随机数?
- 我可以在Java中设置enum起始值吗?
- 无法安装gem -未能建立gem本地扩展-无法加载这样的文件——mkmf (LoadError)
- 如何在Ruby中创建文件
- 什么是Ruby文件。开放模式和选项?
- Ruby数组到字符串的转换
- 如何分割(块)一个Ruby数组成X元素的部分?
- Ruby中“or”和||的区别?
- c# vs Java Enum(适合c#新手)
- 如何测试参数是否存在在轨道
- 在Ruby中不创建新字符串而修饰字符串的规范方法是什么?
- RVM不是一个函数,用' RVM use…’不会起作用
- 了解Gemfile。锁文件
- 如何确定一个数组是否包含另一个数组的所有元素