열거형

열거형 (Enumerations)

F#의 열거형(enum)은 정수 계열 타입으로, 값들의 일부 부분집합에 이름표(label)를 붙여 쓰는 방식이에요. 리터럴 대신 열거형을 쓰면 코드가 훨씬 읽기 쉽고 유지보수하기도 좋아집니다. 이번 시간에는 열거형을 선언하고 사용하는 방법을 차근차근 살펴볼게요.

출처: https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/enumerations

본문

열거형이란?

열거형(enumerations)은 enum이라고도 불리며, 값들의 부분집합에 이름표가 붙어 있는 정수 계열 타입이에요. 리터럴 대신 사용할 수 있어서 코드를 더 읽기 쉽고 유지보수하기 좋게 만들어 줍니다.

문법 (Syntax)

type enum-name =
    | value1 = integer-literal1
    | value2 = integer-literal2
    ...

열거형 사용하기

열거형은 단순한 값을 갖는 판별 공용체(discriminated union)와 아주 비슷해 보이지만, 값을 직접 지정할 수 있다는 점이 달라요. 값은 보통 0이나 1에서 시작하는 정수, 또는 비트 위치를 나타내는 정수입니다. 열거형이 비트 위치를 나타내려는 목적이라면 Flags 특성(attribute)도 함께 사용해야 해요.

열거형의 기본 타입은 사용하는 리터럴에 따라 정해져요. 예를 들어 1u, 2u처럼 접미사를 붙이면 부호 없는 정수(uint32) 타입으로 쓸 수 있습니다.

이름 붙은 값들을 참조할 때는 반드시 열거형 타입 이름 자체를 한정자로 사용해야 해요. 즉 enum-name.value1처럼 써야 하고, 그냥 value1이라고 쓸 수는 없습니다. 이 점은 판별 공용체와 다른 부분인데요, 열거형은 항상 RequireQualifiedAccess 특성을 갖기 때문이에요.

다음 코드는 열거형을 선언하고 사용하는 모습을 보여줍니다.

// Declaration of an enumeration.
type Color =
    | Red = 0
    | Green = 1
    | Blue = 2

// Use of an enumeration.
let col1: Color = Color.Red

아래 코드처럼 적절한 연산자를 사용하면 열거형을 기본 타입으로 아주 쉽게 변환할 수 있어요.

// Conversion to an integral type.
let n = int col1

열거형의 기본 타입

열거형 타입이 가질 수 있는 기본 타입은 sbyte, byte, int16, uint16, int32, uint32, int64, uint64, 그리고 char 중 하나입니다.

열거형 타입은 .NET Framework에서 System.Enum을 상속받는 타입으로 표현되는데, System.Enum은 다시 System.ValueType을 상속받아요. 따라서 열거형은 스택에 위치하거나 포함된 객체 안에 인라인으로 저장되는 값 타입이며, 기본 타입의 어떤 값이든 그대로 열거형의 유효한 값이 됩니다. 이 점은 열거형 값에 대해 패턴 매칭을 할 때 중요해요. 이름이 붙지 않은 값까지 잡아내는 패턴을 반드시 제공해야 하기 때문입니다.

enum 함수로 값 생성하기

F# 라이브러리의 enum 함수를 사용하면 미리 정의된 이름 붙은 값이 아닌 다른 값으로도 열거형 값을 만들 수 있어요. enum 함수는 다음과 같이 사용합니다.

let col2 = enum<Color> (3)

기본 enum 함수는 int32 타입과 함께 동작해요. 따라서 다른 기본 타입을 갖는 열거형에는 사용할 수 없습니다. 그런 경우에는 다음과 같이 써야 해요.

type uColor =
    | Red = 0u
    | Green = 1u
    | Blue = 2u

let col3 = Microsoft.FSharp.Core.LanguagePrimitives.EnumOfValue<uint32, uColor>(2u)

추가로, enum의 케이스들은 항상 public으로 내보내집니다. 그래야 C#과 그 외 .NET 플랫폼과 어긋나지 않기 때문이에요.

패턴 매칭과 FS0104 경고

정의된 enum 케이스만으로 전체를 매칭(exhaustive matching)하고 싶다면, #nowarn "104" 지시문으로 경고 FS0104를 억제할 수 있어요. 이렇게 하면 컴파일러가 패턴 매칭 중 선언된 enum 값만 유효한 값으로 취급해서, 모든 값을 빠짐없이 다루고 있다고 확신할 때 전체 매칭을 위한 기본(catch-all) 패턴이 없어도 됩니다.

경고 FS0104("Enums may take values outside known cases.")가 존재하는 이유는, 직접 값을 지정하거나 비트 연산의 결과로 enum에 임의의 기본 타입 값이 할당될 수 있기 때문이에요.

더 알아보기 (Learn more)