enum

enum (Enums)

enum은 각 값에 이름이 붙어 있는 정수 값들의 집합이에요. 예를 들어 볼게요.

enum Color
  Red
  Green
  Blue
end

참고: 이 페이지는 Crystal의 enum에 대한 내용이에요. C enum에 대해서는 C bindings enum을 참고하세요.

enum은 enum 키워드 뒤에 이름을 적어 정의하고, 몸통(body)에 값들을 담아요. 값은 0에서 시작해 하나씩 증가합니다. 기본 값을 덮어쓸 수도 있어요.

enum Color
  Red        # 0
  Green      # 1
  Blue   = 5 # overwritten to 5
  Yellow     # 6 (5 + 1)
end

enum의 각 상수는 enum의 타입을 가져요.

Color::Red # :: Color

기저(underlying) 값을 얻으려면 그 위에 value를 호출해요.

Color::Green.value # => 1

값의 타입은 기본적으로 Int32인데, 바꿀 수 있어요.

enum Color : UInt8
  Red
  Green
  Blue
end

Color::Red.value # :: UInt8

기저 타입으로는 정수 타입만 허용됩니다.

모든 enum은 Enum에서 상속받아요.

출처: Crystal 공식 문서 - Enums

본문

플래그 enum (Flags enums)

enum은 @[Flags] 어노테이션으로 표시할 수 있어요. 이 어노테이션은 기본 값들을 바꿉니다.

@[Flags]
enum IOMode
  Read  # 1
  Write # 2
  Async # 4
end

@[Flags] 어노테이션은 첫 번째 상수의 값이 1이 되게 하고, 이후 상수는 2를 곱해가며 만들게 해요.

암묵적 상수 NoneAll이 이 enum들에 자동으로 추가되는데, None은 값 0을, All은 모든 상수의 "or"된 값(|)을 가져요.

IOMode::None.value # => 0
IOMode::All.value  # => 7

추가로, 일부 Enum 메서드는 @[Flags] 어노테이션을 확인해요. 예를 들어:

puts(Color::Red)                    # prints "Red"
puts(IOMode::Write | IOMode::Async) # prints "Write, Async"

정수에서 enum 만들기 (Enums from integers)

enum은 정수에서 만들 수 있어요.

puts Color.new(1) # => prints "Green"

enum의 상수에 대응하지 않는 값도 허용됩니다. 값의 타입은 여전히 Color지만, 출력하면 기저 값을 얻을 수 있어요.

puts Color.new(10) # => prints "10"

이 메서드는 주로 C의 정수를 Crystal의 enum으로 바꾸기 위한 것이에요.

술어 메서드 (Predicate methods)

enum은 각 멤버에 대해 술어 메서드(predicate method)를 자동으로 정의합니다. 메서드 이름은 String#underscore를 사용해 만들어져요.

참고: 일반 enum의 경우 ==로 동등성을 비교해요. 플래그 enum의 경우 includes?를 호출합니다.

예를 들어:

enum Color
  Red
  Green
  Blue
end

color = Color::Blue
color.red?  # => false
color.blue? # => true

@[Flags]
enum IOMode
  Read
  Write
  Async
end

mode = IOMode::Read | IOMode::Async
mode.read?  # => true
mode.write? # => false
mode.async? # => true

메서드 (Methods)

클래스나 구조체처럼, enum에도 메서드를 정의할 수 있어요.

enum ButtonSize
  Sm
  Md
  Lg

  def label
    case self
    in .sm? then "small"
    in .md? then "medium"
    in .lg? then "large"
    end
  end
end

ButtonSize::Sm.label # => "small"
ButtonSize::Lg.label # => "large"

클래스 변수는 허용되지만 인스턴스 변수는 허용되지 않아요.

사용하기 (Usage)

메서드 매개변수가 enum 타입 제약을 가질 때는, enum 상수나 심볼 중 하나를 받을 수 있어요. 심볼은 enum 상수로 자동 캐스팅되며, 캐스팅에 실패하면 컴파일 타임 오류가 발생합니다.

def paint(color : Color)
  puts "Painting using the color #{color}"
end

paint Color::Red

paint :red # automatically casts to `Color::Red`

paint :yellow # Error: expected argument #1 to 'paint' to match a member of enum Color

이 자동 캐스팅은 case 문에는 적용되지 않아요. case 문에서 enum을 쓰려면 case enum values를 참고하세요.

더 알아보기 (Learn more)