Ruby'de Enums nasıl uygulanır?


324

Enum deyimini Ruby'de uygulamanın en iyi yolu nedir? Java / C # enums gibi (neredeyse) kullanabileceğim bir şey arıyorum.


7
@auramo, iyi soru ve en iyi cevap için mükemmel seçim. Sevin ya da nefret edin, tip güvenliği ve (en azından Ruby'de) yazım güvenliği yok. C # ve daha sonra Java'da enumları keşfettiğimde çok heyecanlandım (bir değer seçin, ancak bunlardan!), Ruby hiçbir durumda bunu yapmanın gerçek bir yolunu sunmuyor.
Dan Rosenstark

2
Bu sorudaki sorun, Java ve C # numaralarının çok farklı şeyler olmasıdır. Java numaralandırma üyesi bir nesne örneği ve bir singleton'dur. Bir Java enum bir kurucuya sahip olabilir. Buna karşılık, C # sıralamaları İlkel değerleri temel alır. Soru soran hangi davranışı arıyor? C # durumunun istenmesi muhtemel olsa da, Java C veya C ++ yerine açıkça belirtilir, bu nedenle bazı şüpheler vardır. Ruby'de 'güvenli' olmanın bir yolu olmadığını öne sürmek için, bu şeffaf bir şekilde yanlıştır, ancak daha sofistike bir şey uygulamanız gerekir.
user1164178

Yanıtlar:


319

İki yol. Semboller ( :foogösterim) veya sabitler ( FOOgösterim).

Değişmez dizelerle kodun silinmesine gerek kalmadan okunabilirliği artırmak istediğinizde semboller uygundur.

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

Önemli olan temel bir değeriniz olduğunda sabitler uygundur. Sadece sabitlerinizi tutmak için bir modül tanımlayın ve ardından bu sabitleri sabitleyin.

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

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

2
Ya bu numaralandırma çok fazla veritabanında depolanırsa? Sembol gösterimi işe yarar mı? Şüpheliyim ...
Phương Nguyễn

Bir veritabanına kaydediyor olsaydım sabitler yaklaşımını kullanırdım. Tabii ki, veriyi DB'den geri çekerken bir çeşit arama yapmanız gerekir. Ayrıca :minnesota.to_s, sembolün dize sürümünü kaydetmek için bir veritabanına kaydederken olduğu gibi bir şey kullanabilirsiniz . Raylar, sanırım, bununla başa çıkmak için bazı yardımcı yöntemler var.
mlibby

7
Bir modül sabitleri gruplandırmak için daha iyi olmaz mıydı - çünkü herhangi bir örneği yapmayacaksınız?
thomthom

3
Sadece bir yorum. Ruby, konvansiyonları adlandırma konusunda biraz acı çekiyor, ancak siz onları gezene kadar onlar hakkında gerçekten açık değil. Numaralandırmaların adları büyük harfle yazılmalı ve modülün sabit bir modül olduğunu bilmek için ruby ​​için modül adının ilk harfi büyük yazılmalıdır.
Rokujolady

3
Tamamen doğru değil. Sabitin ilk harfi büyük yazılmalıdır, ancak tüm harflerin olması gerekmez. Bu bir kongre tercihi meselesidir. Örneğin, tüm modül adları ve sınıf adları aslında sabittir.
Michael Brown

59

Kimsenin ( RAPI geminden hasat edilmiş) aşağıdaki gibi bir şey sunmadığına şaşırdım :

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

Hangi gibi kullanılabilir:

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

Misal:

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

Bu, veritabanı senaryolarında veya C stili sabitler / numaralandırmalarla uğraşırken iyi çalışır ( RAPI'nın kapsamlı olarak kullandığı FFI kullanılırken olduğu gibi).

Ayrıca, karma türü bir çözüm kullanarak yaptığınız gibi sessiz hatalara neden olan yazım hataları hakkında endişelenmenize gerek yoktur.


1
Bu belirli bir sorunu çözmek için harika bir yoldur, ancak kimsenin bunu önermemesinin nedeni, muhtemelen C # / Java numaralandırmalarına benzememesi ile ilgilidir.
mlibby

1
Bu biraz eksik, ancak çözümleri dinamik bir yaklaşımla nasıl uygulayabileceğiniz konusunda güzel bir ipucu veriyor. FlagsAttribute kümesi ile bir C # enum ile benzerlik gösterir, ancak yukarıdaki sembol / sabit tabanlı çözümler gibi, birçok kişinin bir cevabıdır. Sorun, niyetinde karıştırılan orijinal sorudur (C # ve Java birbirinin yerine kullanılamaz). Ruby'de nesneleri sınıflandırmanın birçok yolu vardır; doğru olanı seçmek çözülmekte olan soruna bağlıdır. İhtiyacınız olmayan körü körüne çoğaltan özellikler yanlış yönlendirilmiştir. Doğru cevap bağlama bağlıdır.
user1164178

52

Bunu yapmanın en deyimsel yolu sembolleri kullanmaktır. Örneğin:

enum {
  FOO,
  BAR,
  BAZ
}

myFunc(FOO);

... sadece sembolleri kullanabilirsiniz:

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

Bu numaralardan daha açık uçlu, ama Yakut ruhuna iyi uyuyor.

Semboller de çok iyi performans gösterir. Eşitlik için iki simgeyi karşılaştırmak, örneğin, iki dizeyi karşılaştırmaktan çok daha hızlıdır.


107
Yani Ruby ruhu: "Yazım
hataları

82
Popüler Ruby çerçeveleri, çalışma zamanı meta programlamasına büyük ölçüde güvenir ve çok fazla yükleme süresi kontrolü yapmak Ruby'nin ifade gücünün çoğunu ortadan kaldıracaktır. Sorunlardan kaçınmak için, Ruby programcılarının çoğu, sadece yazım hataları değil, aynı zamanda mantık hataları da bulan test odaklı tasarım uygular.
emk

10
@yar: Dil tasarımı bir dizi ödünleşmedir ve dil özellikleri etkileşime girer. İyi, oldukça dinamik bir dil istiyorsanız Ruby ile devam edin, önce birim testlerinizi yazın ve dilin ruhuyla devam edin. :-) Eğer aradığınız şey bu değilse, her biri farklı ödünler veren düzinelerce mükemmel dil var.
emk

10
@emk, katılıyorum, ama kişisel sorunum Ruby'de kendimi oldukça rahat hissetmem, ancak Ruby'de rahat bir şekilde yeniden düzenleme hissetmiyorum. Ve şimdi birim testleri yazmaya başladığım için (nihayet), her derde deva olmadığını anladım: tahminim 1) Ruby kodunun pratikte sık sık yeniden düzenlenmediğini ve 2) Ruby son olmadığını dinamik diller açısından en doğru çözüm, çünkü otomatik olarak yeniden düzenleme zor. Smalltalk halkı tarafından garip bir şekilde ele geçirilen 2317579 numaralı sorumu görün.
Dan Rosenstark

4
Evet, ancak bu dizeleri kullanmak C # dilinin ruhu içinde olmaz, sadece kötü bir uygulamadır.
Ed S.

38

Aşağıdaki yaklaşımı kullanıyorum:

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

Aşağıdaki avantajlar için beğendim:

  1. Değerleri görsel olarak bir bütün olarak gruplandırır
  2. Bazı derleme zamanı kontrolleri yapar (sadece sembolleri kullanmanın aksine)
  3. Tüm olası değerler listesine kolayca erişebilirim: sadece MY_ENUM
  4. Farklı değerlere kolayca erişebilirim: MY_VALUE_1
  5. Yalnızca Symbol değil, herhangi bir türde değerler olabilir

Semboller daha iyi olabilir, çünkü başka bir sınıfta ( MyClass::MY_VALUE_1) kullanıyorsanız, dış sınıfın adını yazmak zorunda kalmazsınız


4
Bence bu en iyi cevap. İşlev, sözdizimi ve minimum kod yükü Java / C # 'a en yakın gelir. Ayrıca tanımları bir düzeyden daha derine yerleştirebilir ve yine de MyClass :: MY_ENUM.flatten ile tüm değerleri kurtarabilirsiniz. Bir yan not olarak, Ruby'deki sabitler için standart olarak burada büyük harfli isimler kullanacağım. MyClass :: MyEnum bir alt sınıfa başvuru ile karıştırılmış olabilir.
Janosch

@ Janosch, isimleri güncelledim. öneri için teşekkürler
Alexey

Hala biraz kafam karıştı ve bağlantı 410'du (hayır, 404 değil). Bu numaralandırmanın nasıl kullanılacağına dair örnekler verebilir misiniz?
Shelvacu

17

Rails 4.2 veya daha üstünü kullanıyorsanız Rails numaralarını kullanabilirsiniz.

Rails artık varsayılan olarak herhangi bir mücevher eklemeye gerek kalmadan numaralandırmalara sahip.

Bu, Java, C ++ numaralarına çok benzer (ve daha fazla özellik ile).

Alıntı: 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

7
Söylediğiniz gibi - OP Rails kullanmıyorsa (veya nesne daha doğrusu ActiveRecord türünde değilse) yararlı değildir. Sadece benim aşağı oyumu açıklamak hepsi bu.
Ger

2
Bunlar Ruby'deki numaralandırmalar değildir, veritabanınızdaki Numaralandırmalar için bir ActiveRecord arabirimidir. Başka herhangi bir kullanım durumunda uygulanabilecek genelleştirilebilir bir çözüm değildir.
Adam Lassek

Cevabımda bunu hep bahsettim.
vedant

Bu Rails kullanarak IFF en iyi cevaptır.
theUtherSide

(Çalışmak için) bir Rails veritabanında saklanması gerektiğinden ve Conversationsınıfın birçok örneğini oluşturmasına izin verdiği için sevmiyorum - sadece 1 örneğe izin vermesi gerektiğine inanıyorum.
prograils

8

Bu Ruby'deki numaralandırmalara yaklaşımım. Kısa ve tatlı olacaktım, mutlaka en C benzeri değil. Düşüncesi olan var mı?

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


8

Belki de en iyi hafif yaklaşım

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

Bu şekilde değerler, Java / C # 'da olduğu gibi ilişkili adlara sahiptir:

MyConstants::ABC
=> MyConstants::ABC

Tüm değerleri elde etmek için şunları yapabilirsiniz:

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

Bir enum'un sıralı değerini istiyorsanız,

MyConstants.constants.index :GHI
=> 2

1
IMHO, Java'nın kullanımını ve amacını (tip güvenliği) çok benzer bir şekilde çoğaltır, ayrıca tercih olarak sabitler şu şekilde tanımlanabilir:class ABC; end
wik

8

Adamın bu soruyu yayınlamasından bu yana uzun zaman geçtiğini biliyorum, ama aynı soruyu sordum ve bu yazı bana cevap vermedi. Numarayı temsil eden sütun, kolay karşılaştırma ve enum temsil eden sütunu kullanarak arama için tüm ActiveRecord desteği görmek için kolay bir yol istedim.

Hiçbir şey bulamadım, bu yüzden aradığım her şeye izin veren yinum adlı harika bir uygulama yaptım. Tonlarca spesifikasyon yaptı, bu yüzden güvenli olduğundan eminim.

Bazı örnek özellikler:

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

5

Sembollü yazım hataları hakkında endişeleniyorsanız, var olmayan bir anahtarla bir değere eriştiğinizde kodunuzun bir istisna oluşturduğundan emin olun. Bunu aşağıdakileri fetchyerine kullanarak yapabilirsiniz []:

my_value = my_hash.fetch(:key)

veya varolmayan bir anahtar sağlarsanız karma değerini varsayılan olarak bir istisna oluşturarak:

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

Karma zaten varsa, özel durum oluşturma davranışı ekleyebilirsiniz:

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

Normalde, sabitlerle yazım güvenliği konusunda endişelenmenize gerek yoktur. Sabit bir adı yanlış yazarsanız, genellikle bir istisna oluşturur.


Açıkça söylemeden, enum'ları karmalarla taklit ediyor gibi görünüyorsunuz . Bunu söylemek için cevabınızı düzenlemek iyi bir fikir olabilir. (Ben de şu anda Ruby çeteleler gibi bir şey için bir ihtiyaç var ve bunu çözmek için ilk yaklaşım karmaları kullanmaktır: FOO_VALUES = {missing: 0, something: 1, something_else: 2, ...}Bu tanımlar anahtar semboller. missing, somethingVb ve ayrıca ilişkili değerlerin aracılığıyla onları karşılaştırılabilir hale getirir.)
Teemu Leisti

Yani, cevabın en başında bunu söylemeden.
Teemu Leisti

4

Birisi devam etti ve Renum adlı yakut bir mücevher yazdı . En yakın Java / C # benzeri davranışı elde ettiğini iddia ediyor. Şahsen hala Ruby öğreniyorum ve belirli bir sınıfı statik bir numaralandırma, muhtemelen bir karma içeren, google üzerinden tam olarak kolayca bulunamadığını yapmak istediğimde biraz şok oldum.


Ruby'de hiç bir numaralandırmaya ihtiyacım olmadı. Semboller ve sabitler deyimseldir ve aynı sorunları çözer, değil mi?
Chuck

Muhtemelen Chuck; ama yakutta bir numaralandırma yapmak seni o kadar ileri götürmez. Doğrudan bir eşdeğerde insanların en iyi girişimi için sonuçları gösterecektir. Bu da beni meraklandırıyor, belki de kavramın bir araya getirilmesinde hoş bir şey var.
dlamblin

@Chuck Semboller ve sabitler, örneğin bir değerin küçük bir değer kümesinden biri olması gerektiğini zorlamaz.
David Moles

3

Her şey Java veya C # numaralarını nasıl kullandığınıza bağlıdır. Nasıl kullanacağınız Ruby'de seçeceğiniz çözümü dikte edecektir.

Yerel Settürü deneyin, örneğin:

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

9
Neden sembol kullanmıyorsunuz Set[:a, :b, :c]?
Dan Rosenstark

2
Burada sembolleri kullanmak için çok daha iyi uygulama, IMO.
Collin Graves

3

Son zamanlarda Ruby'de Enums'ı uygulayan bir mücevher çıkardık . Benim içinde yazı sorularınızın cevapları bulacaksınız. Ayrıca, uygulamamızın neden mevcut olanlardan daha iyi olduğunu açıkladım (aslında bu özelliğin Ruby'de henüz mücevher olarak birçok uygulaması var).


Açıkça belirtmeden, kendiliğinden artan değerlere izin verir. +1
dimid

3

Başka bir çözüm OpenStruct kullanıyor. Onun oldukça düz ileri ve temiz.

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

Misal:

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

2

Semboller yakut yoldur. Bununla birlikte, bazen bazı şeyler için bazı numaralar ortaya çıkaran bir C kodu veya bir şey veya Java ile konuşmanız gerekir.


#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

Bu daha sonra şu şekilde kullanılabilir


require 'server_roles'

sSymb, sEnum =EnumLike.server_role()

foreignvec[sEnum[:SERVER_WORKSTATION]]=8

Bu elbette soyut yapılabilir ve kendi Enum sınıfımızı yuvarlayabilirsiniz


server_SymbBelirli bir nedenden ötürü (örn. ) Değişkenlerdeki ikinci kelimeyi büyük yazıyor musunuz? Belirli bir sebep olmadıkça, değişkenlerin snake_case_with_all_lower_caseve sembollerin deyimi deyimdir :lower_case.
Andrew Grimm

1
@ Andrew; bu örnek gerçek dünyadan alınmıştır ve ağ protokolü dokümanı xxx_Yyy kullanmıştır, bu nedenle birkaç dilde kod aynı kavramı kullanmıştır, böylece şartname değişikliklerini takip edebilir.
Jonke

1
Kod golf: server_Symb.each_with_index { |e,i| server_Enum[e] = i}. Gerek yok i = 0.
Andrew Grimm

2

Bunun gibi numaralandırmalar uyguladım

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

o zaman kolay işlemler

EnumType.ENUM_1.label

...

enum = EnumType.find_by_id 1

...

valueArray = EnumType.values

2

Bu biraz gereksiz görünüyor, ancak bu, özellikle xml veya bazılarıyla entegre olduğum yerlerde birkaç kez kullandığım bir metodolojidir.

#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

Bu bana ac # enum katılığını verir ve modele bağlıdır.


Bu yaklaşımı tavsiye etmem, çünkü değerleri manuel olarak ayarlamanıza ve siparişi hemen almanızı sağlar :VAL. Bir dizi ile başlamak ve karma kullanarak oluşturmak daha iyi olurdu.map.with_index
DaveMongoose

1
Kesin olan nokta, kendinizi üçüncü taraflar tarafından dikte edilen bir değere bağlamaktır. Bu, kendi başına genişletilebilirlikle ilgili değil, süreç sınırlarınızdaki hesaplanabilirliği etkileyen gereksiz kısıtlamalarla uğraşmakla ilgilidir.
jjk

Doğru tespit! Bu durumda, değerleri belirtmek kesinlikle mantıklıdır, ancak bir anahtarla .keyveya anahtar .invertyerine ters arama yapmaya eğilimliyim :VAL( stackoverflow.com/a/10989394/2208016 )
DaveMongoose 23:19

Evet, bu size geri döndü. Yakutum beceriksiz ve hantaldı. Def kullanmak keyveyainvert
jjk

1

Çoğu insan sembol kullanır (bu :foo_barsözdizimidir). Bir çeşit benzersiz opak değerlerdir. Semboller herhangi bir enum tarzı tipe ait değildir, bu yüzden C'nin enum tipinin gerçekten sadık bir temsili değildir, ancak bu oldukça iyi.


1
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

Çıktı:

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


to_enumsize bir enumera verir tor oysa enumC # / Java anlamda bir enumera olan siyon
DaveMongoose

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

Çıktı:

GOOD

1

Bazen ihtiyacım olan tek şey enum'un değerini getirebilmek ve adını java dünyasına benzer şekilde tanımlayabilmek.

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'

Bu benim için sayım amacına hizmet eder ve onu da genişletilebilir tutar. Enum sınıfına daha fazla yöntem ekleyebilir ve viyolaları tanımlanmış tüm numaralandırmalarda ücretsiz olarak alabilirsiniz. Örneğin. get_all_names ve bunun gibi şeyler.


0

Başka bir yaklaşım, aşağıdaki RubyFleebie blog gönderisinde açıklandığı gibi, adlar ve değerler içeren bir karma içeren bir Ruby sınıfı kullanmaktır . Bu, değerler ve sabitler arasında kolayca dönüştürmenize olanak tanır (özellikle belirli bir değerin adını aramak için bir sınıf yöntemi eklerseniz).


0

Türleri gibi numaralandırma uygulamak için en iyi yolu semboller ile olduğunu düşünüyorum çünkü hemen hemen tamsayı gibi davranır (performans söz konusu olduğunda, object_id karşılaştırma yapmak için kullanılır); indeksleme konusunda endişelenmenize gerek yok ve kodunuz xD'de gerçekten düzgün görünüyorlar


0

Tutarlı eşitlik yönetimi ile bir numaralandırmayı taklit etmenin başka bir yolu (Dave Thomas'tan utanmadan benimsenmiştir). Açık numaralandırmaya (semboller gibi) ve kapalı (önceden tanımlanmış) numaralara izin verir.

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.