Enumeration — enum 타입 뒤에 있는 롤

Enumeration — enum 타입 뒤에 있는 롤

enum을 쓰면 이름 붙은 상수 집합을 만들 수 있어요. 그런데 enum에 속한 각 원소는 사실 키(key)와 값(value)의 쌍이에요. 바로 그 enum 페어가 구현하는 롤이 Enumeration이에요.

출처: Raku Documentation — Enumeration

본문

role Enumeration { }

이것은 enum 타입의 enum-페어들이 구현하는 롤이에요. 일반적으로는 상수 집합을 만들고, 그 원소들이 현재 네임스페이스의 상수 심볼이 되도록 하며, 같은 집합에 속한 심볼들 사이의 관계를 세우는 데 쓰여요. 보통 Enumeration은 enum 타입에서 만나게 돼요.

enum norse-gods <Þor Oðin Loki>;
my $one-of-them = norse-gods.pick;
say $one-of-them.^name; # OUTPUT: «(norse-gods)␤»
say $one-of-them ~~ Enumeration; # OUTPUT: «True␤»

하지만 키와 값 사이의 관계를 어떤 식으로든 제한하고 싶다면, 여러분 프로그램에서 직접 쓰는 것도 막히진 않아요.

class DNA does Enumeration {
    my %pairings = %( A => "T",
                      T => "A",
                      C => "G",
                      G => "C" );

    method new( $base-pair where "A" | "C" | "G" | "T" )  {
        self.bless( key => $base-pair,
                    value => %pairings{$base-pair});
    }

    multi method gist(::?CLASS:D:) {
        return "$!key → $!value";
    }

}

enum Chain ();
constant length = 16;
for <A C G T>.roll( length ) -> $letter {
    my DNA $base = DNA.new( $letter );
    Chain.HOW.add_enum_value( Chain, $base );
}

for ^length {
    my $base = Chain.pick;
    say "{$base.key} and {$base.value}";
}

이 코드에서 DNAEnumeration 롤을 수행해요. 이 관점에서 보면 하나의 (key, value) 쌍인 셈이죠. 생성된 DNA 객체들을 써서 enum 타입을 구성하면, 그 요소들을 하나씩 골라낼 수 있어요. 출력은 아래처럼 나와요.

T and A
C and G
T and A
# and so on...

항목은 enum 클래스에 스마트매치되지만, 그 반대는 아니에요.

enum Foo <bar baz>;
say baz ~~ Foo;  # OUTPUT: «True␤»
say Foo ~~ bar;  # OUTPUT: «False␤»

enum 클래스에 동작하는 메서드

Rakudo 컴파일러 2021.04 릴리스부터 enum 클래스를 인스턴스화된 Map 객체로 간주할 수 있어요. 즉 enum 클래스에 keys, values, kv, pairs, antipairs, invert를 쓸 수 있고 기대한 결과를 얻을 수 있어요.

enum Norse-gods <Þor Oðin Freija>;
say Norse-gods.keys; # OUTPUT: «(Þor Oðin Freija)␤»

method enums

method enums()

enum 값들의 Map을 반환해요. enum 타입과 어떤 키 모두에서 동작해요.

enum Mass ( mg => 1/1000, g => 1/1, kg => 1000/1 );
say Mass.enums; # OUTPUT: «Map.new((g => 1, kg => 1000, mg => 0.001))␤»
say g.enums;    # OUTPUT: «Map.new((g => 1, kg => 1000, mg => 0.001))␤»

enum 키에 동작하는 메서드

method key

Enumeration 속성이에요.

enum Norse-gods <Þor Oðin Freija>;
say Freija.key; # OUTPUT: «Freija␤»

method value

이것은 Enumeration 속성이에요.

enum Norse-gods <Þor Oðin Freija>;
say Oðin.value; # OUTPUT: «1␤»

값은 enum 타입이 0부터 시작해 자동으로 할당해요. Oðin은 enum에서 두 번째라서 1을 받아요.

method kv

multi method kv(::?CLASS:D:)

enum-페어의 키와 값을 담은 리스트를 반환해요.

say g.kv; # OUTPUT: «(g 1)␤»

method pair

method pair(::?CLASS:D:)

이것을 Pair로 반환해요.

say g.pair; # OUTPUT: «g => 1␤»

method CALL-ME

multi method CALL-ME(|)

enum 값이 주어지면 Enumeration 인스턴스를 반환해요.

enum Mass ( mg => 1/1000, g => 1/1, kg => 1000/1 );
say Mass(1/1000); # OUTPUT: mg

method pick

multi method pick(::?CLASS:U:)
multi method pick(::?CLASS:U: \n)
multi method pick(::?CLASS:D: *@pos)

정의된 클래스에 동작하며, 하나의 원소를 골라 그것을 제거해요.

say Norse-gods.pick() for ^3;  # OUTPUT: «Þor␤Freija␤Oðin␤»

method roll

multi method roll(::?CLASS:U:)
multi method roll(::?CLASS:U: \n)
multi method roll(::?CLASS:D: *@pos)

정의된 클래스에 동작하며, 원소를 제거하지 않고 하나 또는 n개를 골라요.

say Norse-gods.roll() for ^3;  # OUTPUT: «Freija␤Freija␤Oðin␤»

method pred

method pred(::?CLASS:D:)
say Freija.pred;  # OUTPUT: «Oðin␤»

method succ

method succ(::?CLASS:D:)
say Oðin.succ;  # OUTPUT: «Freija␤»

method Numeric

multi method Numeric(::?CLASS:D:)

enum 값을 받아 Numeric으로 변환한 결과를 반환해요.

enum Numbers ( cool => '42', almost-pi => '3.14', sqrt-n-one => 'i' );
say cool.Numeric;       # OUTPUT: «42␤»
say almost-pi.Numeric;  # OUTPUT: «3.14␤»
say sqrt-n-one.Numeric; # OUTPUT: «0+1i␤»

값이 Numeric으로 변환될 수 없으면 예외가 던져진다는 점을 주의하세요.

method Int

multi method Int(::?CLASS:D:)

enum 값을 받아 Int로 변환한 결과를 반환해요.

enum Numbers ( cool => '42', almost-pi => '3.14', sqrt-n-one => 'i' );
say cool.Int;           # OUTPUT: «42␤»
say almost-pi.Int;      # OUTPUT: «3␤»
try say sqrt-n-one.Int;
say $!.message if $!;   # OUTPUT: «Cannot convert 0+1i to Int: imaginary part not zero␤»

값이 Int로 변환될 수 없으면 예외가 던져진다는 점을 주의하세요.

method Real

multi method Real(::?CLASS:D:)

enum 값을 받아 Real로 변환한 결과를 반환해요.

enum Numbers ( cool => '42', almost-pi => '3.14', sqrt-n-one => 'i' );
say cool.Real;           # OUTPUT: «42␤»
say almost-pi.Real;      # OUTPUT: «3.14␤»
try say sqrt-n-one.Real;
say $!.message if $!;    # OUTPUT: «Cannot convert 0+1i to Real: imaginary part not zero␤»

값이 Real로 변환될 수 없으면 예외가 던져진다는 점을 주의하세요.

method ===

multi infix:<===> (Enumeration:D \a, Enumeration:D \b)

Enumeration 심볼의 동등성 검사예요.

say Norse-gods.pick() === Freija for ^3; # OUTPUT: «False␤False␤True␤»

출처: Raku Documentation — Enumeration