· KLDP.org · KLDP.net · KLDP Wiki · KLDP BBS ·
perldoc/perlsyn


1. 번역문서정보

1.1. 원저자 및 번역자

원저자 : 정확히 알 순 없지만 Perl Documentation Team 일 것이다.
번역자 : redneval@kldp.org

1.2. 영문원본 출처

링크 : http://perldoc.perl.org/perlsyn.html
분류 및 이름 : Perl 5.8.8 documentation - Language reference - perlsyn

1.3. 저작권 및 라이센스

본 번역문서의 번역부분에 해당되는 부분의 원 저작권은 redneval@kldp.org 에 있다. 다만, 저작권에 따른 모든 권리는 Free Software Foundation (FSF) 로 이양한다.

본 번역문서는 영문 perldoc의 라이센스에 따라 GPL을 따른다. 그러므로, 본 번역문서의 GPL버전은 영문 perldoc의 GPL버전을 따른다. 만약, 영문 perldoc의 GPL버전이 바뀌면, 본 번역문서 또한 그 바뀐 버전으로 바꿔서 사용할 수 있다.

1.4. 링크

펄에 관한 다른 문서를 보고 싶다면 perldoc을 참고하라.

2. 번역문서

2.1. 이름

perlsyn - 펄 문법

2.2. 설명

펄 프로그램은, 맨 위에서부터 맨 끝까지 순차적으로 실행되는 일련의 선언들과 실행문들로 구성된다. 다만, 루프, 서브루틴, 그리고 다른 제어구조를 통해 코드의 순서를 뛰어넘을 수도 있다.

펄은 자유로운 형식의 프로그래밍 언어이며, 포맷과 들여쓰기를 원하는 방식으로 할 수 있다. (포맷과 들여쓰기가 아니라) 공백문자들이 주로 토큰들을 구분하는 역할을 하는데, 이는 포맷과 들여쓰기가 중요한 문법의 일부를 차지하는 파이썬과 같은 언어들과는 다르다.

펄의 문법적 요소들 중 많은 것들이 선택적이다. 함수호출을 할 때 괄호가 없어도 되고, 변수는 선언되지 않아도 되는 등, 명시적인 요소를 빼버려도 된다. 이런 것을 DWIM (Do What I Mean)이라고 하는데, 이런 것이 프로그래머가 편안한 스타일로 코드작성을 하거나 lazy하도록 허용한다.

펄은 많은 다른 언어에서 문법과 컨셉을 빌려왔다. awk, sed, C, Bourne Shell, Smalltalk, Lisp 그리고 심지어는 영어로부터. 다른 언어들도 펄로부터 문법(특히 정규표현식 확장)을 빌려갔다. 그러므로 다른 언어로 프로그래밍하더라도, 펄의 친숙한 부분을 볼 수 있을 것이다.


2.2.1. 단어설명

  • 문장 또는 실행문 또는 ~문 (statement) : 펄에서의 문장은 실행문을 의미한다.
  • 선언(declaration) : 선언은 실행문의 한 종류가 아니라, 선언을 수행하는 부분만을 의미한다. 그러므로 선언문은 선언과 문장(실행문)의 합으로 이루어진다.
  • 토큰(token) : 변수, 연산자, 기타 문법코드 등을 구성하는 하나의 기본 단위를 말한다.
  • 포맷(format) : 들여쓰기, 줄바꿈 등의 code convention을 일컫는다.
  • 선택적(optional) : '필수적'의 반대말이다.
  • lazy : '게으른'이 아니고, '코딩을 최소화하는'으로 봄이 옳을 것 같다. 이는 보는 사람의 견해에 따라 다르게 번역될 소지가 있으므로 그냥 두어야 한다.
  • 블락(block) : '복합 실행문'항을 참조하라.
  • report format : 아마도 모듈에서 함수를 export하는 부분을 말하는 것 같다.
  • 단순 실행문(simple statement)과 복합 실행문(compound statement) : 복합 실행문은 블락구조를 포함하는 실행문을 일컫는다.
  • 참조범위(scope) : 의미를 명확히 하기 위해 '범위'대신 '참조범위'라는 단어를 선택하였다.
  • proper : 이 단어는 원래 의미와 다르게 번역될 소지가 있으므로 그냥 두어야 한다.


2.2.2. 선언

펄에서 선언을 해야할 유일한 것은 report format과 서브루틴이다. (때때로는 심지어 서브루틴의 선언도 필요없다.) 변수선언을 하면, 값을 대입하기 전까지는 변수는 undef값(정의되지 않은 값)을 가진다. 만약 변수를 숫자로 다루면 undef는 0값으로 다뤄진다. 문자열로 쓰인다면 빈 문자열인 ""로 다뤄진다. 참조값으로 쓰인다면 그것은 error로 다뤄진다. 만약 옵션(use warning)을 통해 경고기능을 활성화하면, undef를 문자열이나 숫자로 다룰때마다 uninitialized value 라는 경고메시지를 볼 것이다. 마지막으로 다음과 같이 불린값(참 또는 거짓)으로 쓰일 경우를 보자.

    my $a;
    if ($a) {}

이런 경우, 경고메시지는 발생하지 않는다. (왜냐면 이런 경우 변수의 값이 정의되었느냐를 살피고 경고를 하는 것이 아니고, $a의 값이 참인지만을 보기 때문이다.) ++ , -- , += , -= , .= 같은 연산자들의 경우 좌변값이 정의되지 않았더라도 경고메시지는 발생하지 않는다. 예를 들면 다음과 같다.

    my $a;
    $a++;

선언을 위한 키워드(my, local 등)는 실행문이 올 수 있는 어느 위치에서든 놓일 수 있다. 그러나 그 실행문의 실행에는 아무런 영향을 주지 않는다. 선언은 컴파일 시간에 영향이 발생하기 때문이다. 보통은 모든 선언문이 스크립트의 맨 앞이나 맨 뒤에 오게 된다. 그런데, my 키워드로 선언된 private 변수를 사용할 때, 그 변수와 같은 블락에 존재하는 모든 코드와 서브루틴은 그 변수에 접근할 수 있다는 점을 주의해야한다.

서브루틴을 선언함으로써, 서브루틴이 마치 리스트 연산자인 것처럼 "sub 서브루틴이름"이라고 함으로써 서브루틴을 정의하지않고 단지 선언만 하는 것이 가능하다.

    sub myname;
    $me = myname $0             or die "can't get myname";

첨언을 하자면, myname() 함수는 단항 연산자가 아닌 리스트 연산자로 다뤄진다는 것이다. 그러므로 위의 예에서 || 대신에 or 를 사용했음에 유의하자. 그러나, 만약 "sub myname ($)"로 선언을 했다면 myname() 함수는 단항 연산자처럼 동작하므로 || 말고도 or 또한 사용할 수 있다.

서브루틴 선언은 또한 require문 또는 use문을 사용하여 불러올 수 있다. 이에 대한 자세한 사항은 perlmod를 보기 바란다.

실행문들은 변수들의 선언을 포함할 수 있다. 그러나 변수를 선언하는 것과는 별개로, 선언문은 일반적인 실행문의 역할을 한다. 이것은 컴파일타임효과/런타임효과 둘 모두를 가지고 있다는 뜻이다.

#로 시작하는 부분부터 줄의 마지막까지가 주석이 되고, 이 부분은 무시된다. 다만 문자열이나 정규표현식 내부의 #은 예외이다.

모든 단순 실행문은 세미콜론으로 끝난다. 다만, 블락의 마지막 실행문은 예외이며, 이 경우에는 세미콜론은 선택적으로 사용할 수 있다. 하지만 나중에 블락의 끝에 추가적인 실행문을 추가하는 경우가 생길 수 있으므로, 세미콜론을 쓰기를 권장한다. 첨언을 하자면, eval {} 와 do {} 같은 연산자들은 복합 실행문같이 생겼지만, 실제로는 아니다. 그러므로 이 연산자가 실행문의 마지막에 위치한다면, 명시적 종료문자인 세미콜론이 필요하다.


2.2.3. 참(true)과 거짓(false)

숫자 0, 문자열 "0" 또는 "", 빈 리스트 (), 그리고 undef는 boolean으로 다뤄질 때, false값을 갖는다. 이 5가지 경우를 제외한 모든 다른 값은 true값을 가지게 된다. true에 Negate연산자인 !과 not의 연산을 취하면 특수한 false값을 가지게 된다. 이 특수한 false 값은 문자열로는 "", 숫자로는 0으로 다뤄진다.


2.2.4. 실행문 수식어

단순 실행문 뒤에는 선택적으로 하나의 수식어가 올 수 있다. 수식어의 위치는 실행문 뒤, 세미콜론의 바로 앞이 된다. 가능한 수식어는 다음과 같다.

    if EXPR
    unless EXPR
    while EXPR
    until EXPR
    foreach LIST

EXPR은 "조건(문)"이라고 부른다. 그것의 참/거짓 값에 따라서 그 수식어가 어떻게 동작하는지 결정하게된다.

if로 시작되는 수식어는 그 조건이 참값을 가질 경우(에만) 실행문을 한 번 실행한다. unless의 경우는 반대로 동작한다. 즉, 조건이 거짓값을 가질 경우(에만) 실행문을 한 번 실행한다.

    print "Basset hounds got long ears" if length $ear >= 10;
    go_outside() and play() unless $is_raining;

foreach 수식어는 일종의 반복문이다. LIST의 각각의 요소에 대해 실행문을 한번씩 실행한다. 이때, 실행문 내에서 각각의 요소는 $_라는 변수를 통해 다룰 수 있다.

    print "Hello $_!\n" foreach qw(world Dolly nurse);

while 수식어는 EXPR이 참값을 가지는 동안에 실행문을 반복하여 실행한다. until은 그 반대로 동작한다. until 수식어는 EXPR이 거짓값을 가지는 동안에 실행문을 반복하여 실행한다.

    # Both of these count from 0 to 10.
    print $i++ while $i <= 10;
    print $j++ until $j >  10;

while과 until수식어에서 조건문은 실행문이 실행되기 전에 먼저 계산된다. 하지만 do {} 구문을 사용하면 실행문을 먼저 실행할 수 있다. 지금은 쓰지말 것을 권하는 do-SUBROUTINE 구문의 경우도 마찬가지로 서브루틴이 먼저 실행된다. 그래서 다음과 같이 루프를 쓸 수 있다.

    do {
        $line = <STDIN>;
        ...
    } until $line  eq ".\n";

자세한 것은 do 함수에 관한 문서를 보라. 첨언하자면, 밑에서 다루게 될 루프 제어 실행문(next, last)은 do {} 구문을 지원하지 않음을 밝힌다. 왜냐하면, 수식어는 루프 라벨을 갖지 않기 때문이다. 이 점은 유감이다. 그래서 next를 사용하여 그런 기능을 구현하려면 do {} 구문 안에 또 다른 블락이 필요하고, last의 경우는 do {} 구문 밖에 또 다른 블락이 필요하다. 그러므로 next의 경우는 단지 이중 괄호를 사용하면 된다.

    do {{
        next if $x == $y;
        # do something here
    }} until $x++ > $z;

last의 경우는 조금 더 복잡하게 처리해야 한다.

    LOOP: {
            do {
                last if $x = $y**2;
                # do something here
            } while $x++ <= $z;
    }

경고 : my 선언문을 실행문 수식어와 같이 쓰지 말아라. 즉, "my $x if ... "과 같이 조건부 선언문을 사용하지 말아라. 이런 실행문에 대해 perl의 동작이 정의되지 않았기 때문이다. 어쩌면 perl의 버전에 따라 다르게 동작할지도 모른다.


2.2.5. 복합 실행문

펄에서는, 일련의 실행문에 블락이라고 불리는 참조범위를 설정할 수 있다. 때때로 블락은 실행문을 포함하고 있는 파일에 의해서 설정된다. 그리고 때때로는 (예를 들어 eval 함수의 경우) 문자열의 범위에 의해 설정된다.

그러나 일반적으로 블락은 중괄호라고 불리는 '{' 와 '}' 에 의해서 설정된다. 이를 BLOCK이라고 부르겠다.

다음의 복합 실행문을 사용하여 실행흐름을 제어할 수 있다.

    if (EXPR) BLOCK
    if (EXPR) BLOCK else BLOCK
    if (EXPR) BLOCK elsif (EXPR) BLOCK ... else BLOCK
    LABEL while (EXPR) BLOCK
    LABEL while (EXPR) BLOCK continue BLOCK
    LABEL until (EXPR) BLOCK
    LABEL until (EXPR) BLOCK continue BLOCK
    LABEL for (EXPR; EXPR; EXPR) BLOCK
    LABEL foreach VAR (LIST) BLOCK
    LABEL foreach VAR (LIST) BLOCK continue BLOCK
    LABEL BLOCK continue BLOCK

첨언하면, C나 파스칼과는 다르게, 위의 제어문에 들어가게 되는 BLOCK은 단순 실행문으로 대체할 수 없다. 예를들어, if (EXPR) STATEMENT 와 같은식으로 중괄호 없이 쓸 수는 없다는 뜻이다. 중괄호를 사용하지 않고 조건문을 쓰려면 다른 방법을 써야한다.

    if (!open(FOO)) { die "Can't open $FOO: $!"; }
    die "Can't open $FOO: $!" unless open(FOO);
    open(FOO) or die "Can't open $FOO: $!";     # FOO or bust!
    open(FOO) ? 'hi mom' : die "Can't open $FOO: $!";
                        # a bit exotic, that last one

if문의 동작은 알아보기 쉽다. 왜냐하면 BLOCK은 항상 중괄호로 둘러싸이므로, if-else문에는 어떠한 모호함도 존재하지 않게 된다. (if-else문의 동작방식은 영어단어 'if'와 'else'의 단어뜻과 일치하므로 영어를 안다면 쉽게 이해할 수 있을 것이다.) 만약 if 대신에 unless를 사용하면 조건문은 반대의 의미를 갖는다. (위의 '실행문 수식어'편에서 unless는 if와 반대로 동작함을 이미 설명하였다.)

while문은 EXPR이 참값을 갖는 동안 BLOCK을 계속하여 실행한다. until문은 EXPR이 거짓값을 갖는 동안 BLOCK을 계속하여 실행한다. LABEL은 선택적이다. 만약 LABEL을 사용한다면 식별자와 그 뒤에 콜론 ':' 을 쓰면 된다. LABEL 식별자는 next, last, redo 같은 루프제어문이 루프를 구분하는데 이용된다. LABEL을 생략하면 루프제어문은 그것을 포함한 가장 안쪽의 루프에 대해 작용하게 된다. LABEL을 찾기 위해서 런타임시에 동적으로 call-stack을 찾을 수도 있다. 이런 무모한 행위는 use warnings 또는 -w 옵션을 사용한다면 경고메시지를 띄우게 된다.

만약 continue BLOCK 구문을 사용한다면, 루프의 조건문이 다시 실행되기 직전에 BLOCK 이 다시 실행된다. 그러므로 루프 변수의 값을 증가시키는데 사용할 수 있다. next문에 의해서 다시 루프가 실행될 때도 BLOCK 이 실행된다.


2.2.6. 루프 제어

next문은 루프의 다음 반복문을 실행하게 한다.

    LINE: while (<STDIN>) {
        next LINE if /^#/;      # discard comments
        ...
    }

last문은 즉시 루프를 빠져나가게 한다. 이때는 continue 블락은 실행되지 않는다.

    LINE: while (<STDIN>) {
        last LINE if /^$/;      # exit when done with header
        ...
    }

redo문은 조건문이 참/거짓인지 보지 않고 루프를 다시 실행한다. 이때 continue 블락은 실행되지 않는다. 입력이 무엇이었는지에 따라 예외적으로 처리하고 싶어하는 프로그램에 의해 redo문이 사용된다.

예를들어, /etc/termcap과 같이 파일을 처리할 때, 입력의 마지막 문자가 백슬래쉬로 다음 줄이 더 있음을 알릴 때, 이를 건너뛰고 다음 줄을 입력으로 받고 싶을 것이다.

    while (<>) {
        chomp;
        if (s/\\$//) {
            $_ .= <>;
            redo unless eof();
        }
        # now process $_
    }

이는 축약버전이고, 명시적인 표현을 사용하여 다시 작성하면 다음과 같다.

    LINE: while (defined($line = <ARGV>)) {
        chomp($line);
        if ($line =~ s/\\$//) {
            $line .= <ARGV>;
            redo LINE unless eof(); # not eof(ARGV)!
        }
        # now process $line
    }

첨언을 하자면, 만약 위의 코드에 continue 블락이 사용되었다면, if문의 조건문의 값이 false값인 줄(즉, 백슬래쉬로 끝나지않는 줄)에 대해서만 그 블락이 실행된다 (redo문은 continue블락을 실행하지 않으므로). continue문은 line counter를 초기화하거나 PATTERN? 연산자를 초기화할 때 종종 사용된다.

    # inspired by :1,$g/fred/s//WILMA/
    while (<>) {
        ?(fred)?    && s//WILMA $1 WILMA/;
        ?(barney)?  && s//BETTY $1 BETTY/;
        ?(homer)?   && s//MARGE $1 MARGE/;
    } continue {
        print "$ARGV $.: $_";
        close ARGV  if eof();           # reset $.
        reset       if eof();           # reset ?pat?
    }

until은 while의 반대가 된다. 그러나 첫 루프를 돌기 전에 조건문을 확인하는 것은 마찬가지이다.

if 나 unless 안에서 루프제어문은 동작하지 않는다. 왜냐면 그건 루프가 아니기 때문이다. '실행문 수식어'항에서 보았듯이, 이중 중괄호를 사용함으로써 루프제어문을 사용할 수 있다.

    if (/pattern/) {{
        last if /fred/;
        next if /barney/; # same effect as "last", but doesn't document as well
        # do something here
    }}

이는 블락은 실행을 한 번하는 루프와 같기 때문에 가능하다. '기본 BLOCK과 Switch문'을 참조하라.

펄 4에서 사용할 수 있었던 while/if BLOCK BLOCK 은 펄 5에서는 사용할 수 없다. if BLOCK 은 if (do BLOCK) 의 형태로 바꿔라.


2.2.7. For루프

펄로 작성한 C방식의 for루프는 다음과 같고,

    for ($i = 1; $i < 10; $i++) {
        ...
    }

이는 다음과 동일하다.

    $i = 1;
    while ($i < 10) {
        ...
    } continue {
        $i++;
    }

위 둘에는 약간의 다른 점이 있다. for루프에서 my키워드를 통해 선언된 변수의 참조범위는 정확히 for루프가 된다.

보통의 배열인덱스를 사용하는 루프와는 다르게, for문은 한 가지 기능이 더 있다. 다음 예의 for문의 조건문을 보면, 명시적으로 STDIN의 EOF를 확인하지 않고, 단지 <STDIN>를 사용하는 것만으로도 암시적으로 그 기능을 수행하고 있다.

    $on_a_tty = -t STDIN && -t STDOUT;
    sub prompt { print "yes? " if $on_a_tty }
    for ( prompt(); <STDIN>; prompt() ) {
        # do something
    }

즉, for루프에서 readline 또는 <EXPR> 로 입력을 조건문에 사용하는 것은 다음과 동일한 결과를 낳는다. 이러한 특성은 while루프의 조건문에 대해서도 마찬가지이다.

    for ( prompt(); defined( $_ = <STDIN> ); prompt() ) {
        # do something
    }


2.2.8. Foreach루프

foreach루프는 list에 대해서 반복문을 수행하고, 그 list의 각각의 요소를 차례로 VAR로 설정한다. 만약 변수가 my 키워드와 함께 온다면, 참조범위는 그 루프가 된다. 그렇지 않다면, 그 변수는 암시적으로 루프에 대한 지역변수가 되며, 루프를 빠져나갈때 루프가 실행되기 전의 값을 갖게 된다. 만약 그 변수가 이전에 my로 선언되었다면, 전역변수 대신에 그 변수를 사용하게 된다. 그러나 이 경우에도 루프의 지역변수로 사용된다. 이 암시적 지역변수화는 foreach루프 내에서만 효력을 미친다.

foreach는 사실상 for키워드와 동일하다. 그러므로 가독성을 위해 foreach를 사용하던가 간결함을 위해 for를 사용할 수 있다. 만약 VAR가 생략되면 각각의 요소는 $_로 설정된다.

LIST의 요소는 좌변값이 될 수 있다. 즉 VAR값을 수정함으로써 LIST의 요소의 값을 바꿀 수 있다. 만약 LIST의 요소는 좌변값이 아닌 경우는, 그 요소의 값을 바꿀 수 없다. 즉, foreach루프의 index 변수는 그 리스트의 각각의 요소의 암시적인 별명이 된다.

경고: 만약 LIST의 일부분이 배열인 경우는, 루프 내에서 요소를 더하거나 뺄 때(예를 들어 splice를 사용하여) foreach가 어떻게 동작해야할지 혼란스러워한다. 그러므로 그렇게 하지 말아라.

tie를 사용한 변수나 특수변수를 VAR의 변수로 사용하지 말아라.

다음은 for문을 어떻게 사용하는지 보여주기 위한 예제이다.

    for (@ary) { s/foo/bar/ }

    for my $elem (@elements) {
        $elem *= 2;
    }

    for $count (10,9,8,7,6,5,4,3,2,1,'BOOM') {
        print $count, "\n"; sleep(1);
    }

    for (1..15) { print "Merry Christmas\n"; }

    foreach $item (split(/:[\\\n:]*/, $ENV{TERMCAP})) {
        print "Item: $item\n";
    }

어떤 알고리즘을 C 프로그래머가 펄로 작성한다면 아마 다음과 같이 할 것이다.

    for (my $i = 0; $i < @ary1; $i++) {
        for (my $j = 0; $j < @ary2; $j++) {
            if ($ary1[$i] > $ary2[$j]) {
                last; # can't go to outer :-(
            }
            $ary1[$i] += $ary2[$j];
        }
        # this is where that last takes me
    }

반면에 펄 프로그래머가 관용어구를 사용하여 좀더 편안한 방식으로 작성한다면 다음과 같을 것이다.

    OUTER: for my $wid (@ary1) {
    INNER:   for my $jet (@ary2) {
                next OUTER if $wid > $jet;
                $wid += $jet;
             }
          }

어떤 것이 더 쉬워보이는가? 두번째 방식은 더 깔끔하고, 안전하며, 빠르다. 두 번째 방식이 가독성이 더 높으므로 코드가 깔끔하다. 안쪽루프와 바깥쪽루프의 사이에 새로운 코드를 덧붙이는 경우, 그 새로운 코드가 실수로 실행되지 않을 수도 있다. 두 번째 방식에서 next문은 안쪽루프를 종료하는 방식이 아니라 명시적으로 바깥쪽 루프를 실행한다. 그러므로 더 안전하다. 그리고 펄은 for방식의 루프보다 foreach방식의 루프를 더 빠르게 실행한다.


2.2.9. 기본 BLOCK과 Switch문

BLOCK은 라벨이 있건 없건 그 자체로 "한번 실행되는 루프"와 같다. 그러므로 블락을 빠져나가거나 다시 실행하는데 루프제어문을 사용할 수 있다. eval{}과 sub{} 그리고 (사람들의 기대와는 다르게) do{} 에 대해서는 예외가 된다. continue 블락은 선택적이다.

BLOCK구조는 switch문을 만드는데 특히 좋다.

    SWITCH: {
        if (/^abc/) { $abc = 1; last SWITCH; }
        if (/^def/) { $def = 1; last SWITCH; }
        if (/^xyz/) { $xyz = 1; last SWITCH; }
        $nothing = 1;
    }

펄에는 공식적인 switch문이 없다. 왜냐하면 이미 switch문과 마찬가지로 동작하는 몇 가지 방법이 이미 있기 때문이다.

다만, 펄 5.8부터는 다음과 같이 하면 Switch 확장기능을 사용할 수 있다.

        use Switch;

하지만 이를 사용한 switch문은 최대한의 속도를 내지는 못한다. 왜냐면 그렇게 사용한 switch문은 언어를 구성하는 부분은 아니기 때문이다. (실제 구현은 source filter을 통해 이루어져있다.) 그러나 아무튼 이런 방식도 사용가능하고, 그것은 매우 유연하게 동작한다.

위에서의 BLOCK구조외에도, 다음과 같이 쓸 수 있다.

    SWITCH: {
        $abc = 1, last SWITCH  if /^abc/;
        $def = 1, last SWITCH  if /^def/;
        $xyz = 1, last SWITCH  if /^xyz/;
        $nothing = 1;
    }

(만약 루프제어'연산자'를 한 표현안에 사용할 수 있다는 점을 생각하면, 저것은 보기보다 이상하지 않다. 저것은 이진 콤마 연산자를 사용한 것이다. perlop의 '콤마 연산자'를 참조하라.)

또는

    SWITCH: {
        /^abc/ && do { $abc = 1; last SWITCH; };
        /^def/ && do { $def = 1; last SWITCH; };
        /^xyz/ && do { $xyz = 1; last SWITCH; };
        $nothing = 1;
    }

또는 좀 더 "proper" switch문에 가깝도록 다음과 같이 쓸 수 있다.

    SWITCH: {
        /^abc/      && do {
                            $abc = 1;
                            last SWITCH;
                       };

        /^def/      && do {
                            $def = 1;
                            last SWITCH;
                       };

        /^xyz/      && do {
                            $xyz = 1;
                            last SWITCH;
                        };
        $nothing = 1;
    }

또는

    SWITCH: {
        /^abc/ and $abc = 1, last SWITCH;
        /^def/ and $def = 1, last SWITCH;
        /^xyz/ and $xyz = 1, last SWITCH;
        $nothing = 1;
    }

또는 심지어 끔직하게

    if (/^abc/)
        { $abc = 1 }
    elsif (/^def/)
        { $def = 1 }
    elsif (/^xyz/)
        { $xyz = 1 }
    else
        { $nothing = 1 }

switch문의 일반적인 관용어를 살펴보자. 정규표현식을 편하게 사용하기위해, 변수를 임시로 $_변수에 할당하는 foreach의 기능을 이용한 다음 방식이 있다.

    SWITCH: for ($where) {
                /In Card Names/     && do { push @flags, '-e'; last; };
                /Anywhere/          && do { push @flags, '-h'; last; };
                /In Rulings/        && do {                    last; };
                die "unknown value for form variable where: `$where'";
            }

또 다른 재미있는 방식은, do 블락을 사용하여 값을 리턴하는 방식이다.

    $amode = do {
        if     ($flag & O_RDONLY) { "r" }       # XXX: isn't this 0?
        elsif  ($flag & O_WRONLY) { ($flag & O_APPEND) ? "a" : "w" }
        elsif  ($flag & O_RDWR)   {
            if ($flag & O_CREAT)  { "w+" }
            else                  { ($flag & O_APPEND) ? "a+" : "r+" }
        }
    };

또는

        print do {
            ($flags & O_WRONLY) ? "write-only"          :
            ($flags & O_RDWR)   ? "read-write"          :
                                  "read-only";
        };

또는 만약 반환값들이 모두 참값을 가지는 경우라면, 다음과 같은 방식을 쓸 수 있다.

    #!/usr/bin/perl
    # pick out jargon file page based on browser
    $dir = 'http://www.wins.uva.nl/~mes/jargon';
    for ($ENV{HTTP_USER_AGENT}) {
        $page  =    /Mac/            && 'm/Macintrash.html'
                 || /Win(dows )?NT/  && 'e/evilandrude.html'
                 || /Win|MSIE|WebTV/ && 'm/MicroslothWindows.html'
                 || /Linux/          && 'l/Linux.html'
                 || /HP-UX/          && 'h/HP-SUX.html'
                 || /SunOS/          && 's/ScumOS.html'
                 ||                     'a/AppendixB.html';
    }
    print "Location: $dir/$page\015\012\015\012";

저 방식은 모든 경우의 반환값들이 참값을 가진다고 확신하는 경우에 쓸 수 있고, 아니라면 앞에서 나온 ?: 를 사용해야한다.

마지막으로, switch문 대신에 서브루틴의 참조값을 가지는 해쉬를 사용해도 된다.


2.2.10. Goto문

(역자 주: 사실 이부분은 번역에서 빼고 싶은 부분이다. Goto는 대부분의 경우 사용하지 않을 것을 권하기 때문이다. 하지만 완전히 빼버리기 보다는 중요한 부분만 번역하기로 하겠다.)

펄은 goto문을 지원한다. 이는 세가지 형태가 있다. goto-LABEL, goto-EXPR, and goto-&NAME 이다. 루프의 LABEL은 goto를 사용할 수 없다. 그건 단지 루프의 이름일 뿐이다.

goto-LABEL은 LABEL로 이름 붙여진 실행문을 찾아서 거기서부터 계속 실행시킨다. 그것은 초기화가 필요한 구조에서 사용될 수 있다. 예를들면 서브루틴이나 foreach루프가 있다. goto문은 동적 참조범위 어디로건 점프할 수 있다. 그것은 서브루틴 밖이 될 수도 있다. 그러나 대부분의 경우 last나 die를 쓰는 것이 더 낫다. 펄의 저자는 goto-LABEL의 필요성을 전혀 느끼지 않고 있다. (이는 펄에 해당되는 것이고, C와는 다른 문제다.)

goto-EXPR는 동적인 라벨이름을 사용할 수 있다. 유지보수성을 생각한다면, 사용하지 않는 것을 권한다.

    goto(("FOO", "BAR", "GLARCH")[$i]);

거의 모든 경우에 있어서 goto를 사용하는 것보다는 next, last, redo를 사용하는 것이 매우 매우 훨씬 낫다. 마찬가지로 에러 처리하는 경우에 있어서도 goto를 사용하는 것보다는 catch/throw를 사용하는 것이 현명하다.


2.2.11. POD: 프로그램 내장 문서

펄은 소스 코드와 문서를 섞는 방식을 제공한다. 줄의 가정 처음에 '='기호와 단어를 넣는 것으로 문서의 시작을 알린다.

    =head1 Here There Be Pods!

그러면 =cut이라는 부분이 나타날 때까지 문서로 간주되므로 컴파일러는 그 부분을 무시하게 된다. 내장 문서의 포맷에 자세한 사항은 perlpod을 참조하라.

다음과 같이 하여 소스 코드와 문서를 섞을 수 있다.

    =item snazzle($)

    The snazzle() function will behave in the most spectacular
    form that you can possibly imagine, not even excepting
    cybernetic pyrotechnics.
    =cut back to the compiler, nuff of this pod stuff!
    sub snazzle($) {
        my $thingie = shift;
        .........
    }

pod 번역기는 pod명령어로 시작하는 단락만을 처리한다. 그러므로 다음 예에서 warn 명령어는 pod 번역기와 컴파일러 모두에게 무시된다.

    $a=3;
    =secret stuff
     warn "Neither POD nor CODE!?"
    =cut back
    print "got $a\n";

그러나 언제까지나 이런 방식으로 동작할 것이라고(warn이 무시된다고) 기대하지 말아라. 모든 pod 번역기가 이런 방식으로 잘 동작되는 것도 아니고, 어쩌면 훗날에는 컴파일러가 이런 부분을 까다롭게 제한할지도 모른다.

주석을 빠르게 작성하려는 용도로 pod 명령어가 사용되기도 한다.


2.2.12. Plain Old Comments (Not!)

(역자주: 이 부분은 번역에서 제외하는 것이 좋겠다.)

ID
Password
Join
You have been selected for a secret mission.


sponsored by andamiro
sponsored by cdnetworks
sponsored by HP

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2009-03-05 16:13:52
Processing time 0.0169 sec