클래스 WhateverCode
클래스 WhateverCode (WhateverCode) (raku-type-whatevercode)
* (Whatever 스타)로 무언가를 '채워 둔' 결과가 바로 WhateverCode 객체예요. Whatever에 대한 자세한 내용은 Whatever 문서를 참고하면 좋아요.
class WhateverCode is Code { }
메서드나 함수가 Whatever 스타를 어떻게 해석할지 직접 제어하고 싶을 때가 있어요. 그럴 땐 Whatever와 WhateverCode 파라미터로 멀티 디스패치를 사용하면 돼요. 아래 예시를 볼게요.
class Cycle {
has $.pos;
has @.vals;
}
multi get-val(Cycle $c, Int $idx) {
$c.vals[$idx % $c.vals.elems]
}
# 두 번째 인자로 * 한 개가 단독으로 오면 어떻게 할지 정의
multi get-val(Cycle $c, Whatever $idx) {
get-val($c, $c.pos);
}
# 표현식 속의 * WhateverCode는 어떻게 할지 정의
multi get-val(Cycle $c, WhateverCode $idx) {
get-val($c, $idx($c.pos));
}
my Cycle $c .= new(:pos(2), :vals(0..^10));
say get-val($c, 3); # OUTPUT: «3»
say get-val($c, *); # OUTPUT: «2»
say get-val($c, *-1); # OUTPUT: «1»
WhateverCode는 Callable 역할을 하므로, 안에 담긴 Callable의 타입을 들여다보는 것도 가능해요. 앞선 예시를 이어서, 시그니처를 검사해 인자가 두 개인 WhateverCode를 처리하는 멀티를 추가할 수 있어요.
# 표현식에 *가 두 개 있을 때는 어떻게 할지 정의
multi get-val(Cycle $c, WhateverCode $idx where { .arity == 2 }) {
get-val($c, $idx($c.pos, $c.vals.elems));
}
say get-val($c, * + * div 2); # 2 + 10/2 = 7
다만 주의할 점이 있어요. 부분 표현식이 자기만의 Whatever 스타 규칙을 가져올 수 있어요.
my @a = (0, 1, 2);
say get-val($c, @a[*-1]) # 2, because the star belongs to the Array class
이렇게 되면 Whatever 스타가 어디에 속하는지가 금방 헷갈리기 쉬워요. 그래서 지나치게 남용하지 않는 게 좋아요.
대신 Callable 타입으로 타입 제약을 걸면, WhateverCode를 포함한 아무 Callable이나 받을 수 있어요.
sub run-with-rand (Callable $code) { $code(rand) };
run-with-rand *.say; # OUTPUT: «0.773672071688484»
run-with-rand {.say}; # OUTPUT: «0.38673179353983»
run-with-rand sub { $^v.say }; # OUTPUT: «0.0589543603685792»
& 시길문자로 파라미터를 잡는 타입 제약도 똑같이 잘 동작하면서 입력이 더 짧아요.
sub run-with-rand (&code) { code time };