루비에서 열거 형을 구현하는 방법은 무엇입니까?


323

루비에서 열거 형 관용구를 구현하는 가장 좋은 방법은 무엇입니까? Java / C # 열거 형과 같이 (거의) 사용할 수있는 것을 찾고 있습니다.


7
@ auramo, 좋은 질문, 최고의 답변을위한 훌륭한 선택. 그것을 좋아하거나 미워하면 유형 안전이없고 (적어도 Ruby에서는) 오타 안전이 없습니다. C #에서 열거 형을 발견하고 나중에 Java에서 열거 형을 발견했을 때 나는 기뻤습니다 (값을 선택하십시오!).
Dan Rosenstark

2
이 질문의 문제점은 Java와 C # 열거 형이 크게 다르다는 것입니다. Java 열거 형 멤버는 객체 인스턴스 및 싱글 톤입니다. Java 열거 형에는 생성자가있을 수 있습니다. 반대로 C # 열거 형은 기본 값을 기반으로합니다. 질문자는 어떤 행동을 찾고 있습니까? C # 사례가 필요한 경우는 있지만 C 또는 C ++ 대신 Java가 명시 적으로 언급되므로 의심의 여지가 있습니다. 루비에서는 '안전'할 수있는 방법이 없다는 것을 암시하는 것은 명백히 잘못된 일이지만 더 복잡한 것을 구현해야합니다.
user1164178

답변:


318

두 가지 방법. 기호 ( :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

2
이 열거 형을 데이터베이스에 너무 저장하면 어떻게됩니까? 기호 표기법이 작동합니까? 의심합니다 ...
Phương Nguyễn

데이터베이스에 저장하는 경우 상수 접근 방식을 사용합니다. 물론 DB에서 데이터를 다시 가져올 때 일종의 조회를 수행해야합니다. :minnesota.to_s데이터베이스에 저장할 때 와 같은 방법으로 기호의 문자열 버전을 저장할 수도 있습니다 . Rails는이 중 일부를 처리 할 수있는 몇 가지 도우미 방법이 있다고 생각합니다.
mlibby

7
상수를 그룹화하지 않는 것이 더 좋을까요? 인스턴스를 만들지 않을 것입니까?
thomthom

3
단지 의견입니다. 루비는 명명 규칙에 대해 약간의 고통을 겪지 만 당신이 그 규칙을 넘어갈 때까지는 분명하지 않습니다. 열거 형의 이름은 모두 대문자 여야하며 모듈 이름의 첫 문자는 루비가 모듈이 상수 모듈임을 알 수 있도록 대문자로 표기해야합니다.
Rokujolady

3
완전히 사실이 아닙니다. 상수의 첫 글자는 대문자 여야하지만 모든 글자가 반드시 필요한 것은 아닙니다. 이것은 컨벤션 선호의 문제입니다. 예를 들어, 모든 모듈 이름과 클래스 이름은 실제로 상수입니다.
Michael Brown

59

아무도 다음과 같은 것을 제공하지 않았다는 것에 놀랐습니다 ( 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

다음과 같이 사용할 수 있습니다.

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가 광범위하게 사용하는 사용할 때와 같이) 잘 작동합니다.

또한 해시 유형 솔루션을 사용할 때와 마찬가지로 오실로 인한 자동 오류 발생에 대해 걱정할 필요가 없습니다.


1
그것은 그 특정 문제를 해결하는 좋은 방법이지만, 아무도 그것을 제안하지 않은 이유는 아마도 C # / Java 열거와 같지 않다는 사실과 관련이 없을 것입니다.
mlibby February

1
이것은 약간 불완전하지만 동적 접근 방식으로 솔루션을 구현하는 방법에 대한 좋은 힌트를 제공합니다. FlagsAttribute가 설정된 C # 열거 형과 비슷하지만 위의 기호 / 상수 기반 솔루션과 마찬가지로 많은 답변 중 하나입니다. 문제는 원래 질문이며, 의도에 혼란을 겪습니다 (C #과 Java는 상호 교환이 불가능합니다). Ruby에서 객체를 항목별로 분류하는 방법에는 여러 가지가 있습니다. 올바른 것을 선택하는 것은 해결되는 문제에 달려 있습니다. 필요하지 않은 기능을 과도하게 복제하는 것은 잘못된 것입니다. 정답은 상황에 따라 달라집니다.
user1164178

52

이를 수행하는 가장 관용적 인 방법은 기호를 사용하는 것입니다. 예를 들어,

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 정신에 잘 맞습니다.

기호도 매우 잘 작동합니다. 예를 들어, 두 기호가 동일한 지 비교하는 것은 두 문자열을 비교하는 것보다 훨씬 빠릅니다.


107
루비의 정신은 : "
타이포

82
널리 사용되는 Ruby 프레임 워크는 런타임 메타 프로그래밍에 크게 의존하므로 너무 많은로드 시간 검사를 수행하면 Ruby의 표현력이 대부분 사라집니다. 문제를 피하기 위해 대부분의 루비 프로그래머는 오타뿐만 아니라 논리 오류도 발견하는 테스트 중심 디자인을 연습합니다.
emk

10
@yar : 언어 디자인은 일련의 트레이드 오프이며 언어 기능은 상호 작용합니다. 훌륭하고 역동적 인 언어를 원한다면 Ruby로 가서 단위 테스트를 먼저 작성하고 언어의 정신을 따르십시오. :-) 만약 그것이 당신이 찾고있는 것이 아니라면, 수십 개의 다른 훌륭한 언어들이 있으며, 각각 다른 상충 관계를 만듭니다.
emk

10
@emk, 나는 동의하지만 개인적 문제는 Ruby에서 매우 편안하다고 느끼지만 Ruby에서 리팩토링하는 것은 기분이 좋지 않다는 것입니다. 이제 단위 테스트를 작성하기 시작했습니다. 마침내 만병 통치약이 아니라는 것을 알고 있습니다. 제 생각에는 1) 루비 코드가 실제로 자주 리팩터링되지 않으며 2) 루비는 끝이 아닙니다. 자동으로 리팩토링하기가 어렵 기 때문에 동적 언어 측면에서 볼 수 있습니다. 이상하게도 스몰 토크 사람들이 물려받은 내 질문 2317579를 참조하십시오.
Dan Rosenstark

4
예, 그러나 이러한 문자열을 사용하는 것이 C # 언어의 정신에 있지는 않지만 단순히 나쁜 습관입니다.
Ed S.

38

나는 다음과 같은 접근법을 사용합니다.

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

다음과 같은 장점이 있습니다.

  1. 시각적으로 하나의 값으로 그룹화합니다.
  2. 컴파일 타임 검사를 수행합니다 (심볼을 사용하는 것과 대조적으로)
  3. 가능한 모든 값 목록에 쉽게 액세스 할 수 있습니다. MY_ENUM
  4. 고유 한 값에 쉽게 액세스 할 수 있습니다. MY_VALUE_1
  5. Symbol뿐만 아니라 모든 유형의 값을 가질 수 있습니다.

다른 클래스 ( MyClass::MY_VALUE_1) 에서 외부 클래스 이름을 사용하는 경우 기호를 사용하면 외부 클래스 이름을 쓰지 않아도됩니다.


4
이것이 가장 좋은 대답이라고 생각합니다. 기능, 구문 및 최소 코드 오버 헤드는 Java / C #에 가장 가깝습니다. 또한 정의를 한 수준보다 깊게 중첩하고 MyClass :: MY_ENUM.flatten을 사용하여 모든 값을 복구 할 수 있습니다. 참고로 여기서는 루비 상수에 대한 표준과 같이 대문자 이름을 사용합니다. MyClass :: MyEnum은 서브 클래스에 대한 참조로 오인 될 수 있습니다.
Janosch

@Janosch, 나는 이름을 업데이트했습니다. 제안 주셔서 감사합니다
Alexey

나는 여전히 약간 혼란스럽고 링크 410'd (아니, 404 아님). 이 열거 형이 어떻게 사용되는지에 대한 예를 들어 주시겠습니까?
Shelvacu

17

Rails 4.2 이상을 사용하는 경우 Rails 열거 형을 사용할 수 있습니다.

Rails는 보석을 포함 할 필요없이 기본적으로 열거 형을 가지고 있습니다.

이것은 Java, C ++ 열거 형과 매우 유사합니다.

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
당신이 말했듯이-OP가 Rails를 사용하지 않는 경우 (또는 더 정확하게는 객체가 ActiveRecord 유형이 아닌 경우) 유용하지 않습니다. 내 downvote를 설명하는 것이 전부입니다.
Ger

2
루비에서는 열거 형이 아니며 데이터베이스의 열거 형에 대한 ActiveRecord 인터페이스입니다. 다른 사용 사례에 적용 할 수있는 일반화 가능한 솔루션이 아닙니다.
Adam Lassek

나는 내 대답에서 그 점을 언급했다.
vedant

이것이 Rails를 사용하는 최고의 답변입니다.
TheUtherSide

Rails 데이터베이스에 저장해야하고 (작동하기 위해) Conversation클래스 의 많은 인스턴스를 만들 수 있기 때문에 마음에 들지 않습니다 . 인스턴스가 하나만 허용해야한다고 생각합니다.
prograils 2016 년

8

이것이 Ruby의 열거 형에 대한 나의 접근 방식입니다. 나는 가장 C 같은 것은 아니지만 짧고 달콤하다. 이견있는 사람?

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

아마도 가장 가벼운 방법은

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

이 방법으로 값은 Java / C #에서와 같이 연관된 이름을 갖습니다.

MyConstants::ABC
=> MyConstants::ABC

모든 값을 얻으려면 다음을 수행하십시오.

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

열거 형의 서수 값을 원한다면 할 수 있습니다

MyConstants.constants.index :GHI
=> 2

1
IMHO 이것은 자바의 사용과 목적 (유형 안전)을 매우 밀접하게 복제하며, 또한 선호에 따라 상수는 다음과 같이 정의 될 수 있습니다.class ABC; end
wik

8

나는 그 사람 이이 질문을 게시 한 지 오랜 시간이 걸렸다는 것을 알고 있지만 같은 질문이 있었고이 게시물은 나에게 답을주지 못했습니다. 열거 형을 나타내는 열을 사용하여 숫자가 나타내는 것, 쉬운 비교 및 ​​조회를위한 모든 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

5

기호가있는 오타가 걱정되는 경우 존재하지 않는 키로 값에 액세스 할 때 코드에서 예외가 발생하는지 확인하십시오. fetch대신 다음을 사용하여이 작업을 수행 할 수 있습니다 [].

my_value = my_hash.fetch(:key)

또는 존재하지 않는 키를 제공하는 경우 기본적으로 해시에서 예외를 발생 시키도록합니다.

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

해시가 이미 존재하면 예외 발생 동작을 추가 할 수 있습니다.

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

일반적으로 상수가있는 오타 안전에 대해 걱정할 필요가 없습니다. 상수 이름을 잘못 입력하면 일반적으로 예외가 발생합니다.


명시 적으로 말하지 않고 해시로 열거 형 에뮬레이션을 옹호하는 것 같습니다 . 그렇게 대답하기 위해 답을 편집하는 것이 좋습니다. (나는 또한 현재 루비에서 열거 형과 같은 필요가 있고, 그것을 해결하는 내 첫 번째 방법은 해시를 사용하는 것입니다 : FOO_VALUES = {missing: 0, something: 1, something_else: 2, ...}이 정의하는 키 상징. missing, something등, 또한 관련 값을 통해 그들을 비교할 수 있습니다.)
티무를 Leisti

대답의 맨 처음에 그렇게 말하지 않고 의미합니다.
Teemu Leisti

4

누군가가 계속해서 Renum 이라는 루비 보석을 썼습니다 . 가장 가까운 Java / C # 같은 동작을 얻는다고 주장합니다. 개인적으로 나는 루비를 배우고 있는데 특정 클래스에 정적 열거 형, 해시가 포함되어 Google을 통해 쉽게 찾을 수없는 해시를 만들고 싶을 때 약간 충격을 받았습니다.


루비에서 열거 형이 필요하지 않았습니다. 기호와 상수는 관용적이며 동일한 문제를 해결합니까?
Chuck

아마도 척; 그러나 루비로 열거 형을 검색하면 그렇게 멀지 않습니다. 그것은 사람들에게 최선의 결과를 직접적으로 보여줍니다. 이 개념을 하나로 묶어 놓는 것이 좋을 수도 있습니다.
dlamblin

@Chuck 기호 및 상수는 예를 들어 값이 작은 값 집합 중 하나 여야한다고 강요하지 않습니다.
David Moles

3

그것은 모두 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"}>

9
왜 기호를 사용하지 Set[:a, :b, :c]않습니까?
Dan Rosenstark

2
여기에서 기호를 사용하는 것이 훨씬 좋습니다.
콜린 그레이브스

3

최근에 우리 는 Ruby에서 Enums 를 구현 하는 gem 을 출시했습니다 . 내 게시물 에는 질문에 대한 답변이 있습니다. 또한 구현이 기존 구현보다 더 나은 이유를 설명했습니다 (실제로 Ruby에는 보석 으로이 기능의 구현이 많이 있습니다).


명시 적으로 언급하지 않고 자체 증분 값을 허용합니다. +1
dimid

3

다른 해결책은 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'

2

기호는 루비 방식입니다. 그러나 때로는 여러 가지에 대한 열거 형을 노출시키는 일부 C 코드 또는 무언가 또는 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 클래스를 굴릴 수 있습니다.


server_Symb특정 이유로 변수 (예 :)에서 두 번째 단어를 대문자로 사용하고 있습니까? 특별한 이유가 없다면 변수가 snake_case_with_all_lower_case이고 기호 가 이면 관용적입니다 :lower_case.
앤드류 그림

1
@ 앤드류; 이 예제는 실제 상황에서 가져온 것으로 네트워크 프로토콜 설명서는 xxx_Yyy를 사용하므로 여러 언어로 된 코드는 동일한 개념을 사용하여 사양 변경을 따를 수 있습니다.
Jonke

1
코드 골프 : server_Symb.each_with_index { |e,i| server_Enum[e] = i}. 필요 없습니다 i = 0.
앤드류 그림

2

나는 그런 열거 형을 구현했다

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

2

이것은 약간 불필요한 것처럼 보이지만 이것은 xml 또는 일부와 통합 할 때 특히 몇 번 사용했던 방법입니다.

#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

이것은 나에게 ac # enum의 엄격함을 제공하며 모델과 관련이 있습니다.


이 방법은 수동으로 값을 설정하고에서 바로 주문을받는 것에 의존하기 때문에 권장하지 않습니다 :VAL. 사용하여 배열로 시작하고 해시를 구성하는 것이 좋습니다 것.map.with_index
DaveMongoose

1
정확한 요점은 제 3자가 지시 한 가치에 자신을 묶는 것입니다. 확장 성 자체가 아니라 프로세스 경계 내에서 계산 능력에 영향을 미치는 외부 제약 조건을 처리해야한다는 것입니다.
jjk

페어 포인트! 이 경우 그것은 확실히 값을 지정하는 것이 합리적이다,하지만 난에 역방향 조회를 할 의향이 될 것 .key또는 .invert오히려보다 :VAL키 ( stackoverflow.com/a/10989394/2208016 )
DaveMongoose

예, 그것은 (당신에게 다시) 공정한 포인트입니다. 내 루비는 우아하고 다루기 어려웠다. def를 사용 key하거나invert
jjk

1

대부분의 사람들은 기호를 사용합니다 ( :foo_bar구문입니다). 그것들은 일종의 독특한 불투명 값입니다. 기호는 열거 형 스타일에 속하지 않으므로 실제로 C의 열거 형을 충실하게 표현하지는 않지만 얻을 수있는만큼 좋습니다.


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

산출:

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


to_enum당신에게 enumera의 제공 토르를 하는 반면, enum는 C #에서 / 자바 감각이 enumera의 인
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)

산출:

GOOD

1

때로는 필요한 것은 열거 형 값을 가져 와서 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 클래스에 더 많은 메소드를 추가하고 정의 된 모든 enum에서 비올라를 무료로 얻을 수 있습니다. 예를 들어. get_all_names와 같은 것들.


0

또 다른 방법은 다음 RubyFleebie 블로그 게시물에 설명 된대로 이름과 값을 포함하는 해시와 함께 Ruby 클래스를 사용하는 것 입니다. 이를 통해 값과 상수 사이를 쉽게 변환 할 수 있습니다 (특히 주어진 값의 이름을 조회하는 클래스 메소드를 추가하는 경우).


0

타입과 같은 열거 형을 구현하는 가장 좋은 방법은 기호로 수행하는 것입니다. 왜냐하면 거의 정수처럼 동작하기 때문입니다 (성능에 관해서는 object_id가 비교에 사용됩니다). 인덱싱에 대해 걱정할 필요가 없으며 코드 xD에서 깔끔하게 보입니다.


0

일관된 평등 처리 (Dave Thomas에서 뻔뻔스럽게 채택)로 열거 형을 모방하는 또 다른 방법. 열린 열거 형 (기호와 유사) 및 닫힌 (사전 정의 된) 열거 형을 허용합니다.

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.