Perl to Raku 가이드 — 특수 변수
Perl to Raku 가이드 — 특수 변수 (Special variables)
Perl에는 $_, $!, @_ 같은 특수(구두점) 변수들이 많아요. Raku로 옮기면 이 변수들이 어떻게 되는지, 그대로 살아남는지 아니면 다른 이름으로 바뀌는지 궁금할 때가 많죠. 이 문서는 Perl 특수 변수와 그 Raku 상당식을 정리한 참고 목록이에요.
본문
아래는 Perl 특수 변수와 그 Raku 상당식을 (되도록) 빠짐없이 비교한 목록이에요. 필요할 때마다 차이점 메모를 덧붙였어요.
참고 (NOTE)
이 문서는 Perl의 특수 변수에서 Raku 상당식으로 안내하려는 시도예요. Raku 특수 변수의 전체 문서는 각각의 Raku 문서를 참고하세요.
특수 변수 (SPECIAL VARIABLES)
일반 변수 (General variables)
$_ (일반 기본 변수)
다행히 $_는 Perl과 마찬가지로 일반 기본 변수예요. Raku에서의 주요 차이점은 이 변수에 메서드를 호출할 수 있다는 거예요. 예를 들어 Perl의 say $_는 Raku에서 $_.say로 쓸 수 있어요. 게다가 기본 변수이므로 변수 이름조차 쓸 필요가 없어요. 앞선 예는 .say만으로도 달성할 수 있어요.
@_ (함수 인자)
Raku에는 이제 함수 시그니처가 있으므로, 인자를 @_에 의존하지 않고 시그니처에 넣을 수 있어요. 사실 함수 시그니처를 쓰면 @_를 사용하면 기존 시그니처를 덮어쓸 수 없다는 오류를 토해내요.
하지만 함수 시그니처를 쓰지 않으면 @_는 Perl에서처럼 함수에 전달한 인자를 담아요. $_와 마찬가지로 메서드를 호출할 수 있어요. 달리 $_와 달리 @_를 그 메서드들이 동작할 기본 변수로 가정할 수는 없어요(즉 @_.shift는 동작하지만 .shift는 안 돼요).
$" (리스트 구분자)
현재 Raku에는 List Separator 변수의 상당식이 없어요. <S28 설계 문서>에 그런 건 없다고 나와 있으니, 기대를 접는 게 좋을 거예요.
$$ (프로세스 ID)
$$는 Raku에서 $*PID로 대체됐어요.
$0 (프로그램 이름)
Raku에서는 $*PROGRAM-NAME으로 프로그램 이름에 접근할 수 있어요.
참고: Raku에서 $0은 정규식 매치에서 첫 번째 캡처 값을 담는 변수예요 (즉 캡처 변수는 이제 $1이 아니라 $0부터 시작해요).
$( (실제 그룹 ID)
Raku에서 그룹 정보는 $*GROUP으로 처리돼요. 이 변수는 +$*GROUP으로, 그룹 이름은 ~$*GROUP으로 얻어요.
$) (유효 그룹 ID)
유효 그룹 ID는 현재 Raku에서 제공되지 않는 것 같아요.
$< (실제 사용자 ID)
Raku에서 사용자 정보는 $*USER로 처리돼요. 이 변수는 $*GROUP 객체가 그룹 정보를 처리하는 것과 비슷해요). 사용자 ID는 +$*USER로, 사용자 이름은 ~$*USER로 얻어요.
$> (유효 사용자 ID)
유효 사용자 ID는 Raku에서 제공되지 않아요.
$; (첨자 구분자)
첨자 구분자 변수는 Raku에 포함되지 않아요. 솔직히 Perl 코드가 이걸 쓰고 있다면 거의 확실히 아주 아주 오래된 코드예요.
$a, $b
Raku에서 $a와 $b는 특별한 의미가 없어요. sort()도 이것들을 특별히 쓰지 않아요. 그냥 평범한 변수예요.
이 기능은 더 다재다능한 자리표시자(placeholder) 파라미터를 가진 블록으로 확장됐어요. 자리표시자 변수는 ^ 트와이질로 만들어요 (예: $^z). bare 블록이나 명시적 파라미터 목록이 없는 서브루틴에서 쓸 수 있어요. 블록의 인자는 자리표시자 변수에 유니코드 순서로 할당돼요. 즉 변수가 블록에 ($^q, $^z, $^a) 순서로 나타나도 ($^a, $^q, $^z) 순서로 할당돼요. 그래서:
sort { $^a cmp $^z }, 1, 5, 6, 4, 2, 3;
# OUTPUT: «(1 2 3 4 5 6)»
sort { $^g cmp $^a }, 1, 5, 6, 4, 2, 3;
# OUTPUT: «(6 5 4 3 2 1)»
for 1..9 { say $^c, $^a, $^b; last }
# OUTPUT: «312»
자리표시자 변수에 대한 더 자세한 내용은 <이 페이지>를 보세요.
%ENV
%ENV는 Raku에서 %*ENV로 대체됐어요. 이 해시의 키는 Perl과 Raku 사이에 정확히 같지 않을 수 있어요. 예를 들어 OLDPWD는 Raku의 %ENV에 없어요.
$] (Perl 버전)
실행 중인 Raku 버전은 $*RAKU 특수 변수가 보관하는데, 이건 객체예요. 실행 버전은 $*RAKU.version으로 얻으며 v6.d 같은 걸 반환해요. Raku 인터프리터의 완전한 문자열화 버전은 $*RAKU.gist로 얻으며 Raku (6.d) 같은 걸 반환해요.
$^F
Raku에는 더 이상 존재하지 않아요.
@F
[NEEDS FURTHER RESEARCH] 현재는 좀 혼란스러워요. 설계 문서 S28은 Perl의 @F가 Raku에서 @_로 대체된다고 시사하지만 그게 어떻게 동작하는지 불분명해요. 다만 Perl to Raku 번역 문서가 -a와 -F 커맨드라인 스위치가 아직 rakudo에 구현되지 않았다고 밝히고 있으니, 지금은 다소 논점이 아닌 문제예요.
@INC
Raku에는 더 이상 존재하지 않아요. 모듈 저장소를 검색하도록 조작하려면 "use lib"를 쓰세요. @INC에 가장 가까운 건 실제로 $*REPO예요. 하지만 Raku의 프리컴파일 능력 때문에 @INC와는 완전히 다르게 동작해요.
# 컴파일 유닛 저장소 목록 출력
.say for $*REPO.repo-chain;
%INC
Raku에는 더 이상 존재하지 않아요. 각 Repository가 어떤 모듈을 이미 로드했는지 기억하는 책임이 있기 때문이에요. 로드된 모든 모듈(컴파일 유닛) 목록은 이렇게 얻을 수 있어요:
use Test;
use MyModule;
say flat $*REPO.repo-chain.map(*.loaded); #-> (MyModule Test)
$^I (in-place 편집)
S28이 $*INPLACE_EDIT을 제안하지만 아직 존재하지 않아요.
$^M
S28이 $*EMERGENCY_MEMORY를 제안하지만 아직 존재하지 않아요.
$^O (OS 이름)
이것은 다소 불분명해요. "운영체제의 이름"이 무슨 뜻인지에 따라 다를 거예요. 설계 문서
"실행 환경"에 대한 정보를 담은 세 개의 주요 객체가 있어요:
$*KERNEL— 실행 중인 OS 커널 정보$*DISTRO— OS 배포판 정보$*VM— Raku의 실행 백엔드 머신 정보
위 모든 객체는 공통 메서드를 가져요:
version— 그 구성 요소의 버전 번호name— 그 구성 요소의 니모닉 이름auth— 그 구성 요소의 알려진 작성자
짧은 예시로, 다음 코드는 위 모든 구성 요소에 대한 정보를 출력해요:
for $*KERNEL, $*DISTRO, $*VM -> $what {
say $what.^name;
say 'release ' ~ $what.version
~ ' named ' ~ $what.name
~ ' by ' ~ $what.auth;
}
# Kernel
# release 4.10.0.42.generic named linux by unknown
# Distro
# release 17.04.Zesty.Zapus named ubuntu by https://www.ubuntu.com/
# VM
# release 2017.11 named moar by The MoarVM Team
위 모든 객체의 name이에요.
이 객체들은 정확히 실행 중인 인스턴스를 식별할 때 유용한 다른 메서드도 전부 가져요. 더 많은 정보를 원하면 위 모두를 인트로스펙트하려면 .^methods를 쓰세요.
%SIG
상당식 변수가 없어요. 신호를 수신했을 때 코드를 실행하려면
$SIG{"INT"} = sub { say "bye"; exit }
signal(SIGINT).tap: { say "bye"; exit }; loop {}
어떤 신호를 받았는지 알고 싶은 일반적인 코드가 있다면:
signal(SIGINT).tap: -> $signal { say "bye with $signal"; exit }; loop {}
이벤트 주도 상황에서 신호를 쓰는 더 관용적인 방법:
react {
whenever signal(SIGINT) {
say "goodbye";
done
}
}
$^T (기준 시간)
Raku에서 $*INIT-INSTANT로 대체됐어요. Perl과 달리 epoch 이후의 초가 아니라, 원자 초(분수 포함)로 측정되는
$^V (Perl 버전)
$]처럼 $*RAKU.version으로 대체됐어요.
${^WIN32_SLOPPY_STAT}
Raku에는 이에 해당하는 것이 없어요.
$^X (실행 파일 이름)
$*EXECUTABLE-NAME으로 대체됐어요. Raku에는 $*EXECUTABLE도 있다는 점에 주의하세요.
정규식 관련 변수
성능 문제
아래에서 보듯 $``, $&, $'는 Raku에서 사라졌고, 주로 $/`의 변형으로 대체됐어요. 이 변수들이 사라지면서 Perl에서의 관련 성능 문제도 적용되지 않아요.
$1, $2, ... (캡처)
이 기존 변수들은 Raku에서 Perl과 같은 일을 해요. 다만 이제 $1이 아니라 $0부터 시작해요. 게다가 이것들은 매치 변수 $/의 인덱스 항목의 동의어예요. 즉 $0은 $/[0]과 동등하고, $1은 $/[1]과 동등해요.
$& (매치)
$/이 이제 $& 동작은 그것을 문자열화해서 얻을 수 있어요. 즉 ~$/로요. $/.Str도 동작해야 하지만, 현재는 ~$/가 더 흔한 관용구예요.
${^MATCH}
이전의 성능 문제가 사라졌으므로 이 변수는 Raku에서 쓸모없어요.
`$`` (prematch)
$/.prematch로 대체됐어요.
${^PREMATCH}
이전의 성능 문제가 사라졌으므로 이 변수는 Raku에서 쓸모없어요.
$' (postmatch)
$/.postmatch로 대체됐어요.
${^POSTMATCH}
이전의 성능 문제가 사라졌으므로 이 변수는 Raku에서 쓸모없어요.
$+ (마지막 괄호 매치)
Raku에는 존재하지 않지만, $/[*-1].Str을 사용해 같은 정보를 얻을 수 있어요 ($/[*-1]은 실제 문자열이 아니라 매치 객체가 될 거예요).
왜 그게 동작하는지 이해하고 싶다면 이 문서들을 보세요: [<[ ] routine>](https://docs.raku.org/routine/[ ]),
$^N (마지막 서브매치 결과)
S28이 $*MOST_RECENT_CAPTURED_MATCH를 제안하지만, $^N에 해당하는 구현된 변수는 없는 것 같아요.
@+ (마지막 매치 끝)
대부분의 정규식 관련 변수처럼, 이 기능은 Raku에서 적어도 부분적으로 $/ 변수로 옮겨졌어요. 혹은 이 경우엔 그 인덱스에 별칭을 두는 번호 변수로요. 오프셋은 .to 메서드로 찾아요. 즉 첫 오프셋은 $/[0].to이고, 이는 $0.to와 동의어예요. Perl이 $+[0]으로 주는 값은 $/.to로 제공돼요.
%+ (마지막 괄호 매치)
다시 $/로 옮겨왔어요. 예전 $+{$match}는 $/{$match}예요.
@- (마지막 매치 시작)
@+가 .to 메서드 사용으로 대체된 것처럼, @-는 $/과 그 변형에 .from 메서드를 사용해 대체됐어요. 첫 오프셋은 $/[0].from 또는 동등한 $0.from이에요. Perl의 $-[0]은 $/.from이에요.
%- (마지막 매치 시작)
%+와 아주 비슷하게, %-{$match} 사용은 $/{$match}로 대체돼요.
$^R (마지막 정규식 코드 결과)
상당식 없음.
${^RE_DEBUG_FLAGS}
상당식 없음.
${^RE_TRIE_MAXBUF}
상당식 없음.
파일핸들 관련 변수
$ARGV
줄을 읽을 때 현재 파일의 이름은 $*ARGFILES.path로 얻을 수 있어요.
@ARGV
@*ARGS가 커맨드라인 인자를 담아요.
ARGV
$*ARGFILES로 대체됐어요.
ARGVOUT
-i 커맨드라인 스위치가 아직 구현되지 않아서 ARGVOUT의 상당식은 아직 없어요.
$, (출력 필드 구분자)
현재 명확한 상당식이 없어요.
$. (입력 줄 번호)
직접적인 대체가 존재하지 않아요.
IO::Path 또는 IO::Handle 타입의 .kv 메서드를 호출해서 인덱스와 값이 섞인 리스트를 얻고 (각 루프마다 2씩 반복) 할 수 있어요:
for "foo".IO.lines.kv -> $n, $line {
say "{$n + 1}: $line"
}
# OUTPUT:
# 1: a
# 2: b
# 3: c
# 4: d
IO::CatHandle 타입($*ARGFILES도 그중 하나)의 경우, on-switch 훅을 사용해 핸들 스위치에서 줄 번호를 리셋하고 수동으로 증가시킬 수 있어요. 이 작업을 단순화하는 IO::CatHandle::AutoLines와 LN 모듈도 참고하세요.
$/ (입력 레코드 구분자)
파일핸들의 .nl-in 메서드로 접근해요. 예: $*IN.nl-in.
$\ (출력 레코드 구분자)
파일핸들의 .nl-out 메서드로 접근해요. 예: $*OUT.nl-out.
$| (출력 자동 플러시)
전역 대안이 없어요. TTY 핸들은 기본적으로 언버퍼드(unbuffered)예요. 다른 핸들은 특정 IO::Handle에 대해 out-buffer를 0으로 설정하거나 open에서 :!out-buffer를 쓰면 돼요.
${^LAST_FH}
Raku에서 구현되지 않았어요.
포맷 관련 변수
Raku에는 내장 포맷이 없어요.
오류 변수
Raku에서 오류 변수가 바뀐 방식 때문에 이들을 여기서 하나씩 상세히 다루지 않을게요. Raku $!이 오류 변수예요." 그게 전부예요. 모든 오류 변수들이 $!에 흡수된 것처럼 보여요. Raku의 나머지처럼 이것도 오류나
특히 $!은 던져진 예외에 대한 정보를 제공해요:
try {
fail "Boooh";
CATCH {
# catch 블록 내부에서
# 예외는 $_ 에 놓인다
say 'within the catch:';
say $_.^name ~ ' : ' ~ $_.message;
$_.resume; # 중단하지 않기
}
}
# catch 블록 밖에서 예외는 $! 에 놓인다
say 'outside the catch:';
say $!.^name ~ ' : ' ~ $!.message;
위 코드는 다음 출력을 만들어요:
within the catch:
X::AdHoc : Boooh
outside the catch:
X::AdHoc : Boooh
따라서 앞서 말했듯 $! 변수는 예외 객체를 담아요.
인터프리터 상태 관련 변수
$^C, $^D, ${^ENCODING}, ${^GLOBAL_PHASE}, $^H, %^H, ${^OPEN}, $^P, ${^TAINT}, ${^UNICODE}, ${^UTF8CACHE}, ${^UTF8LOCALE} — Raku에서 구현되지 않았어요.