Perl to Raku 가이드 — 연산자
Perl to Raku 가이드 — 연산자 (Operators)
Perl의 perlop 문서에서 익숙하게 쓰던 연산자들이 Raku에서는 이름이 바뀌거나 의미가 조금 달라진 경우가 많아요. =>가 화살표가 아니라 페어를 만들고, ->가 파괴(dereference) 대신 다른 의미로 쓰이기도 하죠. 이 문서는 Perl 연산자를 Raku 상당식으로 옮기는 참고용 목록이에요.
본문
아래는 Perl 연산자와 그 Raku 상당식을 (되도록) 빠짐없이 나열한 목록이에요. 필요할 때마다 차이점에 대한 메모를 덧붙였어요.
참고 (NOTE)
이 문서는 연산자를 상세히 설명하지 않아요. Perl의 perlop 문서에 있는 연산자에서 Raku 상당식으로 안내하는 데 집중해요. Raku 상당식의 전체 문서는 <Raku 문서 — Operators>를 보세요.
연산자 우선순위와 결합성 (Operator precedence and associativity)
Raku의 연산자 우선순위 표는 Perl과 꽤 달라서 여기서 상세히 다루지 않아요. 특정 연산자의 Raku 우선순위·결합성을 알아야 한다면
항(項)과 리스트 연산자 (Terms and list operators)
Perl의 perlop 문서에서 단항·리스트 연산자로 분류한 것들은 대개 print나 chdir처럼 함수로도 생각할 수 있는 것들이에요. 그래서 이들에 대한 정보는 <함수 가이드>에서 찾을 수 있어요.
괄호는 여전히 그룹화에 쓰여요. 다만 주의점 하나: Raku에서는 리스트를 만드는 건 괄호가 아니라 쉼표(,)예요. 그래서:
my @foo = 1,2,3,4,5; # 괄호 불필요
.say for 1,2,3,4,5; # 이것도 괄호 불필요
my $scalar = (1); # 리스트가 아님, 쉼표가 없으니
my $list = (1,); # 스칼라 컨테이너 안의 List
화살표 연산자 (The arrow operator)
- Perl의
=>(fat comma)에 대해서는 <쉼표 연산자>를 보세요. - 파괴 연산자
->는 점(dot)으로 대체됐는데, 이 점은 메서드 호출에도 쓰여요. 그래서 Perl의$arrayref->[7]는 Raku에서$arrayref.[7],$user->name은$user.name이 돼요. 참고로 Raku에서 파괴 연산은 드물어요. - Raku는
->를에 를 붙이는 데 사용해요.
자동 증가·자동 감소 (Auto-increment and auto-decrement)
Perl과 동일하게 동작해요. 다만 한 가지 주의할 점은 ++는 succ 메서드를, --는 pred 메서드를 호출해서 동작한다는 거예요. 내장 숫자 타입에서는 특별한 일이 없겠지만, 커스텀 타입은 자신만의 succ/pred를 정의할 수 있어서 그 경우 ++/--가 실제로 뭘 하는지 주의해서 봐야 해요.
거듭제곱 (Exponentiation)
예상대로 동작해요. Perl perlop에서의 주의 사항, 즉 **가 단항 마이너스보다 더 강하게 결합한다는 점(-2**4는 (-2)**4가 아니라 -(2**4)로 평가)은 Raku에서도 동일해요.
기호 단항 연산자 (Symbolic unary operators)
- Perl처럼 단항
!는 논리 부정,-는 산술 부정을 해요.?^는 비트 논리 부정으로, 문서에 따르면!와 동등해요. 이들은 인자를 각각과 으로 강제 변환한다는 점이 관련 있을 수 있어요. - Raku에서 단항
~는 문자열 컨텍스트 연산자예요. 비트 정수 부정은 접두+^를 쓰세요. 2의 보수(two's complement)를 가정해요. +는 Raku에서 인자를 Numeric 타입으로 강제 변환하는 실제 효과가 있어요.- 단항
\는 이제 없어요. 정말 기존 명명된 변수의 '참조'를 얻고 싶다면 아이템 컨텍스트를 쓰면 돼요.$aref = item(@array)처럼요. 더 익숙하게는$를 붙여서$aref = $@array로 쓸 수도 있어요. 주의: 진짜 참조를 얻는 게 아니라, 참조된 객체를 담은 스칼라 컨테이너를 얻는 거예요. - 명명된 서브루틴의 '참조'는
&시길로 얻을 수 있어요.$sref = &foo. 익명 배열·해시·서브는 생성할 때 즉시 기반 객체를 반환해요.$sref = sub { }.
결합 연산자 (Binding operators)
=~와 !~는 각각 ~~와 !~~로 대체됐어요. Perl의 smartmatch에 문제가 있다고 생각했던 분들이라면 Raku에서 훨씬 잘 동작한다는 소식을 반가워하실 거예요. 타입이 강해져서 추측이 줄었기 때문이에요. Raku에서 smartmatch가 어떻게 동작하는지 더 자세한 설명은 <smartmatch 문서>를 참고하세요.
곱셈 연산자 (Multiplicative operators)
이항 *, /, %는 Perl처럼 각각 곱셈·나눗셈·나머지를 해요.
이항 x는 Raku에서 조금 다르고 짝을 이루는 연산자가 있어요. print '-' x 80;은 80개의 대시 문자열을 주지만, Perl의 @ones = (1) x 80;(80개의 "1" 리스트) 동작을 원한다면 @ones = 1 xx 80;을 쓰세요.
덧셈 연산자 (Additive operators)
이항 +와 -는 예상대로 각각 덧셈·뺄셈을 해요.
.이 메서드 호출 연산자이므로, Raku에서 이항 ~는 문자열 연결 연산자로 동작해요.
시프트 연산자 (Shift operators)
<<와 >>는 각각 +<와 +>로 대체됐어요.
명명된 단항 연산자 (Named unary operators)
앞서 언급했듯 이들은 <함수 가이드>에서 찾을 수 있어요.
관계 연산자 (Relational operators)
이 연산자들은 전부 Perl과 동일하게 동작해요.
동등 연산자 (Equality operators)
==와 !=는 모두 Perl과 동일하게 동작해요.
<=>와 cmp는 Raku에서 다른 동작을 해요.
<=>는 숫자 비교를 하지만, Perl의-1,0,1대신Order::Less,Order::Same,Order::More를 반환해요.- Perl의
cmp동작(정수가 아니라객체를 반환한다는 차이만 빼고)을 얻으려면 leg연산자를 쓰면 돼요. cmp는 인자의 기존 타입에 따라<=>또는leg를 수행해요.~~는 Perl처럼 smartmatch 연산자이면서, 앞서 언급했듯 Raku에서는 (그냥) 매치 연산자이기도 해요.
Smartmatch 연산자
Raku에서 smartmatch가 어떻게 동작하는지 더 자세한 설명은 <smartmatch 문서>를 참고하세요.
비트 AND (Bitwise And)
이항 &는 Raku에서 +&예요.
비트 OR와 배타 OR (Bitwise Or and Exclusive Or)
비트 OR는 Perl의 |에서 Raku의 +|로 바뀌었어요. 마찬가지로 비트 XOR ^는 +^인데, 이 연산자는 정수에 대해 동작해요.
C 스타일 논리 AND / C 스타일 논리 OR
변경 없음.
논리 Defined-Or
Raku에서 //로 남아 있어요. 첫 번째 정의된 피연산자를 반환하고, 없으면 마지막 피연산자를 반환해요. 그리고 orelse라는 낮은 우선순위 버전도 있어요.
범위 연산자 (Range operators)
리스트 컨텍스트에서 ..는 범위 연산자로 동작하며 바꿀 필요가 없어야 해요. 다만 유용할 수 있는 제외형 범위 연산자가 있어요:
- infix
..^— 끝점을 제외 - infix
^..— 시작점을 제외 - infix
^..^— 시작점과 끝점 둘 다 제외 - prefix
^— 0에서 시작하며 끝점을 제외
다음 예시는 위 모든 범위 연산자의 효과를 보여줘요 (괄호는 메서드 호출을 허용하기 위해서만 썼어요):
(1..^5).list; # (1 2 3 4)
(1^..5).list; # (2 3 4 5)
(1^..^5).list; # (2 3 4)
(^5).list; # (0 1 2 3 4)
Perl에서 스칼라 컨텍스트의 ..와 ... 연산자는 flip-flop 연산자로 동작해요. 잘 알려지지 않고 덜 쓰이긴 하지만요. Raku에서는 이 연산자들이 각각
조건 연산자 (Conditional operator)
조건 연산자 ? :는 ?? !!로 대체됐어요:
$x = $ok ? $yes : $no; # Perl
$x = $ok ?? $yes !! $no; # Raku
할당 연산자 (Assignment operators)
완전히 문서화되진 않았지만, S03은 수학·논리 할당 연산자가 예상대로 동작한다고 시사해요. 눈에 띄는 변화 하나는 .= 는 왼쪽의 객체(타입 객체일 수도 있음)에 대해 변경 메서드(mutating method)를 호출한다는 점이에요. 그래서 이런 유용한 관용구를 쓸 수 있어요:
class LongClassName {
has $.frobnicate;
}
my LongClassName $bar .= new( frobnicate => 42 ); # 클래스 이름을 반복할 필요 없음
이렇게 하면 $bar가 LongClassName 객체만 담을 수 있다는 걸 보장하면서, 클래스 이름을 반복(그리고 어쩌면 오타를 낼)할 필요도 없어요.
.과 ~의 변화에 따라 ~=는 문자열 연결 할당이에요. 비트 할당 연산자는 숫자·문자열 버전(&= 등 vs &.= 등)으로 나뉘지 않을 가능성이 커요. 그 기능이 Perl에서도 현재 실험적이기 때문이에요 — 다만 이것 역시 명시적으로 문서화되진 않았어요.
쉼표 연산자 (Comma operator)
쉼표 연산자는 대체로 예상대로 동작하지만, 기술적으로 를 만들거나 함수 호출에서 인자를 구분해요. 함수 호출을 메서드 호출로 바꾸는
: 변형도 있어요 — <이 페이지>를 보세요.
=> 연산자(fat arrow)는 Perl의 "fat comma"처럼 왼쪽에 따옴표 없는 (보통) 식별자를 허용하지만, Raku에서는 단순히 구분자로 기능하는 대신
리스트 연산자 (오른쪽) (List operators (rightward))
명명된 단항 연산자와 마찬가지로, 이들은 <함수(Functions)> 아래에서 다뤄져요.
논리 NOT (Logical Not)
!의 낮은 우선순위 버전이에요. !처럼 인자를
논리 AND / 논리 OR·배타 OR
&&의 낮은 우선순위 버전은 Perl에서와 같아요. or는 ||의 낮은 우선순위 버전이고, xor는 ^^의 낮은 우선순위 버전이에요. 추가로 //의 낮은 우선순위 버전인 orelse도 있어요.
따옴표 및 따옴표류 연산자 (Quote and quote-like operators)
- 완전히 리터럴인 문자열을 허용하는 따옴표 연산자:
Q또는「…」. 후자는 키보드에서 찾기 어려울 수 있어요(키보드에 따라).Q따옴표 문자열에서는 백슬래시 이스케이프가 적용되지 않아요. 예:Q{This is still a closing curly brace → \}는 "This is still a closing curly brace → "로 렌더링돼요. q는 예상대로 백슬래시 이스케이프를 허용해요. 예:q{This is not a closing curly brace → \}, but this is → }는 "This is not a closing curly brace → }, but this is →"를 반환해요. Perl에서처럼 동작을 단일 따옴표로 할 수도 있어요.qq는 변수 보간을 허용해요. 다만 기본적으로 스칼라 변수만 보간돼요. 다른 변수를 보간하려면 변수 뒤에 대괄호를 붙여야 해요(소위). 예: @a = <1 2 3>; say qq/@a[] [email protected]/;는 "1 2 3 [email protected]"이 돼요. 해시도 같은 방식으로 보간돼요:%a = 1 => 2, 3 => 4; say "%a{}";는 페어 사이를 공백으로, 각 페어 안의 키와 값을 탭으로 구분한 문자열을 줘요 (그게의 표준 문자열화이고, 해시는 문자열화될 때 Pair 리스트처럼 동작하기 때문이에요). 중괄호를 사용해 Raku 코드를 문자열에 보간할 수도 있어요. 자세한 내용은 을 보세요. qw는 Perl처럼 동작하고«<...>»로 렌더링할 수도 있어요. 예:qw/a b c/는«<a b c>»와 동등해요.- 보간하는
qw버전도 있어요. 바로qqw예요.my $a = 42; say qqw/$a b c/;는 "42 b c"를 줘요. - 셸 따옴표는
qx로 가능하지만, Perl과 달리 백틱이 셸 따옴표를 하지 않고, Perl 변수는qx문자열에서 보간되지 않아요. 셸 명령 문자열에서 Perl 변수를 보간해야 한다면qqx를 쓰면 돼요. qr연산자는 Raku에서 사라졌어요.tr///는 Perl과 비슷하게 동작해요. 주의점은 범위를 다르게 지정한다는 거예요. "a-z"라는 범위 대신 "a..z", 즉 Perl의 범위 연산자를 쓰는 거예요.tr///에는 더 잘 문서화된 메서드 버전인.trans가 있어요..trans는 페어 리스트를 써요:$x.trans(['a'..'c'] => ['A'..'C'], ['d'..'q'] => ['D'..'Q'], ['r'..'z'] => ['R'..'Z']);..trans사용법에 대한 훨씬 더 자세한 설명은 <여기>에서 찾을 수 있어요.y///상당식은 없어졌어요.- Heredoc은 Raku에서 다르게 지정해요. 따옴표 연산자와 함께
:to를 쓰는데, 예를 들어q:to/END/;는 "END"로 끝나는 heredoc을 시작해요. 마찬가지로 따옴표 연산자에 따라 이스케이프·보간을 얻어요. 즉Q면 리터럴,q면 백슬래시 이스케이프,qq면 보간이에요.
입출력 연산자 (I/O operators)
Raku의 입출력에 대한 자세한 내용은
«<...>»이 Raku의 quote-words 구성이므로, <>는 파일에서 줄을 읽는 데 쓰이지 않아요. 파일명으로 .lines를 호출하면 돼요. 즉 my @a = "filename".IO.lines; 또는 my $fh = open "filename", :r; my @a = $fh.lines; (후자에서는 읽기 전용으로 파일을 열기 위해 :r을 쓰고 있어요). 반복적으로 처리하려면 이렇게 for 루프를 쓰면 돼요:
for 'huge-csv'.IO.lines -> $line {
# Do something with $line
}
여기서 ->의 사용에 주목하세요. 그건 Block 문법의 일부이고, Raku에서 if, for, while 등에 필요해요.
파일 전체를 스칼라로 슬러프(slurp)하려면 — 놀랍게도 — .slurp 메서드를 쓰면 돼요. 예:
my $x = "filename".IO.slurp;
# ... 또는 ...
my $fh = open "filename", :r;
my $x = $fh.slurp;
<특수 변수 가이드>에서 언급하듯, ARGV 매직 입력 파일핸들은 $*ARGFILES로, 커맨드라인 인자의 @ARGV 배열은 @*ARGS로 대체됐어요.
No-ops
1 while foo();는 Perl과 같은 방식으로 동작하지만 경고를 만들어요. Raku에서는 관용구를 Nil while foo();로 써요.
비트 문자열 연산자 (Bitwise string operators)
위에서 각각 문서화했지만 정리하면:
- 비트 정수 부정은 접두
+^. 비트 불리언 부정은?^. - 비트 AND는
+&. - 비트 정수 OR는
+|. 비트 정수 XOR는 infix+^. 비트 불리언 OR는?|. - 왼쪽·오른쪽 시프트는
+<와+>.