在Ruby中实现枚举习语的最佳方法是什么?我正在寻找一些东西,我可以使用(几乎)像Java/ c#枚举。
当前回答
我知道自从那个人发布这个问题已经有很长时间了,但我也有同样的问题,这篇文章没有给我答案。我想要一种简单的方法来查看数字代表什么,便于比较,最重要的是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
其他回答
另一种解决方案是使用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'
我使用以下方法:
class MyClass
MY_ENUM = [MY_VALUE_1 = 'value1', MY_VALUE_2 = 'value2']
end
我喜欢它的优点如下:
它在视觉上将值组合为一个整体 它执行一些编译时检查(与仅使用符号相比) 我可以很容易地访问所有可能值的列表:只有MY_ENUM 我可以轻松地访问不同的值:MY_VALUE_1 它可以有任何类型的值,而不仅仅是Symbol
符号可能会更好,因为如果你在另一个类中使用它,你不必写外部类的名称(MyClass::MY_VALUE_1)
符号是红宝石之道。然而,有时我们需要与一些C代码或Java进行对话,这些代码或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类
有时我所需要的是能够获取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之类的。
查看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
推荐文章
- 如何从枚举中选择一个随机值?
- 我如何让红宝石打印一个完整的回溯而不是截断一个?
- c#中枚举中的方法
- 如何使用RSpec的should_raise与任何类型的异常?
- 如何创建退出消息
- 忽略GEM,因为没有构建它的扩展
- 在Gem::Specification.reset期间未解决的规格:
- Delete_all vs destroy_all
- 双引号vs单引号
- 用any可以吗?'来检查数组是否为空?
- Rails获取“each”循环的索引
- 为什么在c++中声明enum时使用typedef ?
- Ruby类实例变量与类变量
- 在Ruby中输出数组到CSV
- 我如何在MySQL中添加更多的成员到我的enum类型列?