perltrap - Perl 의 부주의에 의한 함정
voltar para o topo
가장 큰 함정은,
use warnings 혹은
-w 스위치를 사용하는 것을
잊어버린 다는 것입니다.
perllexwarn 과
perlrun 을 참조해주세요.
두번째로 큰 함정은, 당신의 프로그램 전체를
use strict 기반으로 실행하지 않는다는 것입니다.
세번째의 함정은 Perl 의 이 패키지에서의 변경점을 읽지않는 다는 것입니다.
perldelta 를 참조해주세요.
(awk 함정)
awk 에 익숙한 사람은, 아래와 같은 것에 특히 주의해주세요:
Perl 프로그램은, 1번만 실행됩니다; 입력줄 마다 실행되는 것이 아닙니다.
-n 이나 -p 를 사용해 암묵적인 루프를 사용할 수 있습니다.
English모듈은
use English;
처럼 해서 로드하면,
awk 에서 그렇듯
(
$/ 같은) 특수변수를 ($RS 같은) 이름으로 참조할 수 있습니다.
자세한 내용은
perlvar 를 참조해주세요.
Perl 에서는, 모든 단순구문(simple statement) 의 끝에 세미콜론이 필요합니다
(블록의 마지막에 놓여진 경우를 뺍니다).
줄바꿈은 구문을 나누는 것이 아닙니다.
if 나
while 에서는 카리퍼런스가 필요합니다.
Perl에서 변수는 “$”``나“@”나“%”로 시작합니다.
배열의 첨자는 0에서 시작합니다.
substr() 나
index() 로 문자열의 위치도
마찬가지입니다.
배열의 첨자가 숫자값인가 문자열인가를 결정하지는 않습니다.
해쉬(연상배열)의 값은, 단순히 참조하는 것만으로는 존재하지 않습니다.
비교를 문자열에 의해 수행할 것인가, 숫자값에 의해 수행할 것인가를
결정하지 않으면 안됩니다.
입력을 읽어들이는 것만으로는 split 는 수행되지 않습니다.
배열으로의 split 는 스스로 수행합니다.
또,
split() 연산자의 인수는
awk 와는 다릅니다.
보통, 최근 줄은 $0 가 아닌 $_ 에 있습니다.
일반적으로, 줄바꿈은 뺄 수 없습니다
($0에는 실행되고 있는 프로그램의 이름이 있습니다).
perlvar 를 참조해주세요.
$<
digit> 는 필드를 참조하지 않습니다. 이것은
직전에 수행한 패턴매칭의 부분문자열을 참조합니다.
print() 문은,
$, 나
$\ 에 값을 설정하지 않는 한 필드 구분자나
레코드 구분자를 넣지않습니다. English 모듈을 사용하고 있다면,
$OFS 나 $ORS 에 대해서 설정하는 것으로도 OK입니다.
파일에 대해서 출력하기 전에는, 그 파일을 새로 오픈해 두지 않으면 안됩니다.
번위연산자는 ``..''이지, 콤마가 아닙니다. 컴마연산자는 C와 같은 행동을 합니다.
매치연산자는 ``=~'' 이지, ``~''가 아닙니다.
(``~'' 는 C와 마찬가지로, 1의 보수를 얻는 연산자입니다).
승의 연산자는 ``**'' 이지 ``^''가 아닙니다.
``^''는 C와 마찬가지로, XOR입니다.
(
awk 가 기본적으로 C와 호환하는 것이 아닌 것에 신경쓰일지도 모르겠습니다.)
연속연산자는 ``.''이지, 빈문자열이 아닙니다
(빈문자열을 사용해버리면,
/pat/ /pat/이, 그 3번째의 슬래쉬가 제산연산자로
해석되어버리기에 올바르게 해석될 수 없게 됩니다.
Perl 의 문자구문해석기는 ``/'', ``?'', ``>'' 같은 연산자에 대해
다소 문맥의존을 하고 있습니다. 실제 ``.'' 자신도 숫자값으로 시작하게 될
가능성도 있습니다)
키워드
next,
exit,
continue 의 행동이 다릅니다.
아래의 수치의 행동이 다릅니다.
Awk Perl
ARGC scalar @ARGV (compare with $#ARGV)
ARGV[0] $0
FILENAME $ARGV
FNR $. - something
FS (whatever you like)
NF $#Fld, or some such
NR $.
OFMT $#
OFS $,
ORS $\
RLENGTH length($&)
RS $/
RSTART length($`)
SUBSEP $;
$RS 에 정규표현을 설정할 수는 없습니다. 가능한 것은 문자열뿐입니다.
이상하다 생각할 때에는 awk 의 구문을 a2p 를 통해서,
출력된 것을 보는 것은 어떨까요?
(C/++ 의 함정)
지적인 C와 C++ 의 프로그래머는 아래의 내용에 주의해야합니다:
if 나 while 에는 카리퍼런스가 필요합니다.
else if 가 아니라 elsif 를 사용하지 않으면 안됩니다.
C 의 break 와 continue 는 Perl에서는 각각 last 와
next 가 됩니다.
C 와는 달리, 이것들은 do {} while 구문에서는 사용하지 않습니다.
Loop Control in perlsyn 을 참조해주세요.
swtich 문은 없습니다(단, 그때(on the fly)에 만들어버리는 것은 간단합니다;
Basic BLOCKs and Switch Statemnts in perlsyn 를 참조해주세요).
Perl 에서는 변수가 “$”나 “@”나 “%”로 시작합니다.
커맨트의 시작은, ``#''이지, ``/*''나 ``//''가 아닙니다.
Perl은 C/C++ 의 커멘트를 제산연산자, 종단하지 않는 정규표현,
정의성화연산자로써 해석될지도 모릅니다.
어떤 주소를 얻을 수는 없습니다. Perl 에는 비슷하 연산자인
백슬래쉬가 있지만, 이것은 참조를 생성합니다.
ARGV 는 대문자가 아니면 안됩니다. $ARGV[0] 가 C에서의 argv[1]에
상당하고, argv[0] 에 맞는 것은 $0 입니다.
link(), unlink(), rename() 등의 시스템 호출은, 성공시에 0이 아닌
0을 반환합니다. (단, system() 은 성공시에 0을 반환합니다)
시그널 핸들러는, 시그널번호가 아닌 시그널이름을 다룹니다.
사용할 수 있는 시그널이름은, kill -l 로 확인해 주세요.
(sed 의 함정)
열심히 한
sed 프로그래머는 아래에 대해서 주의해야합니다:
Perl 의 프로그램은, 1번만 실행됩니다; 입력줄 마다 실행되지 않습ㄴ디ㅏ.
-n 나 -p 를 사용해 암묵적인 루프를 사용할 수 있습니다.
치환에 의한 후방참조에는 ``\''가 아닌 ``$''를 사용합니다.
``('', ``)'', ``|'' 같은 패턴매치의 메타캐릭터는
그 앞에 백슬래쉬를 할 필요가 있습니다.
범위연산자는 ... 이지 컴마가 아닙니다.
(shell 의 함정)
꼼꼼한 셸프로그래머는 아래의 대해서 주의해야합니다:
역따옴표 연산자는, 커맨드 안에 따옴표가 있어도 변수의 전개를 수행합니다.
역따옴표 연산자는 csh 와는 달리, 반환된 값을 변환하지 않습니다.
셸 (특히 csh) 는, 커맨드라인마다 몇 단계의 치환을 수행합니다.
Perl 은 쌍따옴표, 역따옴표, 앵글브라켓, 검색패턴 같은 특정의 구조에서만
치환을 수행합니다.
셸은 한번에 조금씩 해석을 수행합니다.
Perl 은 실행전에 프로그램 전체를 컴파일합니다
(컴파일 시에 실행되는 BEGIN 블록을 빼고).
인수는 $1, $2 등이 아니라, @ARGV에서 얻을 수 있습니다.
환경변수는, 자동적으로는 독립한 스칼라변수로써 이용할 수 없습니다.
The shell's test uses ``='', ``!='', ``<'' etc for string comparisons and ``-eq'',
``-ne'', ``-lt'' etc for numeric comparisons. This is the reverse of Perl, which
uses eq, ne, lt for string comparisons, and ==, != < etc
for numeric comparisons.
(TBT)
(Perl 의 함정)
실용적인 Perl 프로그래머는 아래에 대해서 주의해야합니다:
많은 연산자가 리스트컨텍스트와 스칼라 컨텍스트에서 행동이 변하는 것을
잊지 않도록 해주세요. 자세한 내용은 perldata 를 참조해주세요.
그냥 단어, 특히 모든 것이 소문자인 것은 가능한한 사용하지 말아주세요.
본 것만으로는 그 단어가 함수인지 문자열인지 판단할 수 없습니다.
문자열에는 따옴표를, 함수호출에는 괄호를 붙이면 당황하지 않을 겁니다.
내장 함수의 어느 것이(chop() 나 chdir()) 같은 단항연산자로,
어느것이(print() 나 unlink()) 같은 리스트연산자인 것인가는
본 것만으로는 알 수 없습니다.
(프로토타입이 없으면, 유저 정의 서브루틴은 리스트 연산자로써만
정의되고, 단항연산자는 될 수 없습니다).
perlop 와 perlsub 를 참조해주세요.
몇개인가의 함수가 $_ 나 @ARGV 등을 기본값으로 하고 있습니다만,
같은 것을 기대하는 다른 함수가 기본값이 되지 않는 다는 것을 기억하는 것에
힘든 타이핑이 필요할 겁니다.
<FH> 구조는 파일핸들이 아닌, 그 핸들에 대한 줄 읽음의 조작
(readline operation)입니다.
while 루프의 조건식의 안에 이 파일 읽기만이 있는 경우에는
읽어들이는 데이터는 $_ 에 대입됩니다.
while (<FH>) { }
while (defined($_ = <FH>)) { }..
<FH>; # 데이터는 버려집니다.
=~ 이 필요한 곳에서 C,=> 을 사용하지 않는 다는 것을 잊지 말아주세요.
이것들 두개의 구조는 상당히 다릅니다.
$x = /foo/;
$x =~ /foo/;
do {} 구조는, 루프제어를 사용할 수 있는 진짜 루프가 아닙니다.
로컬 변수는,
my() 로 끝난 곳에서는 이것으로 끝나게 하는 것
(사용하지 않는 장소에 대해서는,
perlform 을 참조해주세요).
local() 을 사ㅇ하면 글로벌 변수에 대해 로컬한 값을 줄 수 있지만,
동적 스코프의 부작용의 가능성은 그대로 입니다.
모듈에 있는 export 된 변ㅜ를 국소화하면, 그 export 된 값은 변경되지 않습니다.
로컬 이름은 새로운 값의 별명(alias)가 되지만, 외부이름은 원래의 값의
별명 그대로 입니다.
(Perl4 에서 Perl5 로 갈때의 함정)
실용적인 Perl4 프로그래머는
아래에 든 Perl4와 Perl5의 차이에 특유한 함정에 주의하는 편이 좋을 겁니다.
아래는 순서가 같지 않은 리스트입니다.
- Discontinuance, Deprecation, and BugFix? traps
-
-
수정된 perl4 의 버그나, 없어진 perl4의 스펙, perl5 에서 스펙이 바뀐 것.
-
- 구문해석에 관한 함정
-
-
새로운 구문해석기에 의해 발생되는 것.
-
- 숫자값에 관한 함정
-
숫자값이나 산술연산자에 관한 함정
- General data type traps
-
-
perl의 표준적인 데이터형태에 내포된 함정.
-
- Context Traps - scalar, list contexts
-
-
리스트 안의 컨텍스트나, 스칼라 문/선언에 관한 함정.
-
- 우선순위의 함정
-
-
구문해석, 평가, 코드의 실행의 우선순위에 관계한 함정.
-
- General Regular Expression Traps using s///, etc.
-
-
패턴매칭의 스펙에 관한 함정.
-
- Subroutine, Signal, Sorting Traps
-
-
시그널 및 시그널핸들러, 일반적인 서브루틴, 정렬,
-
정렬을 위한 서브루틴에 관한 함정.
-
- OS Traps
-
-
OS특유의 함정.
-
- DBM Traps
-
-
dbmopen() 의 사용이나, dbm의 구성에 관한 함정.
-
- Unclassified Traps
-
-
그 이의외 함정
-
만약 여기에서 든 리스트에는 없는 변환의 함정의 예를 발견하면,
그것을 <
perlbug@perl.org> 에 보내주세요.
그리고, 적어도 이것들의 몇개는
use warnings 프라그마나
-w 스위치로 어느정도 메꿔줄 수 있는 것에 주의해주세요.
perl4 에서, 없어지거나 수정된 것들에서
package test;
$_legacy = 1;
package main;
print "\$_legacy is ",$_legacy,"\n";
# perl4 의 출력: $_legacy is 1
# perl5 의 출력: $_legacy is
Double-colon valid package separator in variable name
더블콜론은, 변수이름의 안에서 패키지구분자가 되었습니다.
이 때문에, 아래의 예에서는 perl4와 perl5에서는 행동이 바뀌었습니다.
이것은 패키지가 없기때문입니다.
$a=1;$b=2;$c=3;$var=4;
print "$a::$b::$c ";
print "$var::abc::xyz\n";
# perl4 の出力: 1::2::3 4::abc::xyz
# perl5 出力: 3
:: 는 지금은, (이것이 버그 분류되어야하는 가는 별도로)
패키지 구분자로써 취급되게 되었습니다.
(여기에서는 낡은 패키지 구분자는 ' 를 사용하고 있습니다)
$x = 10;
print "x=${'x}\n";
# perl4 의 출력: x=10
# perl5 의 출력: Can't find string terminator "'" anywhere before EOF
보통 패키지 이름을 포함하는 것으로, 이 문제를 피할 수 있고, perl4 와의
호환성을 유지할 수 있습니다.
$x = 10;
print "x=${main'x}\n";
$: 의 해석에 대해서는, 우선순위의 함정도 참조해주세요.
2nd and 3rd args to splice() are now in scalar context
splice() 의 제2, 제3의 인수는
(낙타 책에 있는 대로) 리스트컨텍스트가 아닌
스칼라 컨텍스트로 평가되게 됩니다.
sub sub1{return(0,2) } # 요소 2개의 리스트를 반환
sub sub2{ return(1,2,3)} # 요소 3개의 리스트를 반환
@a1 = ("a","b","c","d","e");
@a2 = splice(@a1,&sub1,&sub2);
print join(' ',@a2),"\n";
# perl4 의 출력: a b
# perl5 의 출력: c d e
Can't do goto into a block that is optimized away
최적화에 의해 없어져버린 듯한 블록의 안에
날라든
goto 는 사용할 수 없게 되었습니다.
goto marker1;
for(1){
marker1:
print "Here I is!\n";
}
# perl4 prints: Here I is!
# perl5 errors: Can't "goto" into the middle of a foreach loop
Can't use whitespace as variable name or quote delimiter
공백을 변수의 이름이나, 따옴표 구조의 구분자로 사용하는 것은
구문적으로 정당한 것이 아닌 게 되었습니다.
$a = ("foo bar");
$b = q baz;
print "a is $a, b is $b\n";
# perl4 의 출력: a is foo bar, b is baz
# perl5 errors: Bareword found where operator expected
while/if BLOCK BLOCK gone
낡은 while/if BLOCK BLOCK 구문은 더이상 지원하지 않습니다.
if { 1 } {
print "True!";
}
else {
print "False!";
}
# perl4 의 출력: True!
# perl5 errors: syntax error at test.pl line 1, near "if {"
** binds tighter than unary minus
** 연산자의 우선순위는, 단항의 마이너스보다도 높아졌습니다.
이것은 이전부터 문세에는 그랬었지만, 실제는 달랐었습니다.
print -4**2,"\n";
# perl4 の出力: 16
# perl5 の出力: -16
foreach changed when iterating over a list
배열에서는 없는 리스트에 대한 반복으로
어느 때의
foreach{} 의 의미가 바뀌었습니다.
이전은 그런 리스트는 임시적인 배열에 대입되었지만,
지금은 그렇지 않습니다(효율상의 이유입니다).
이것은 현재로는 값의 복사에 대해 반복을 하는 것이 아닌
실제의 값에 대해 반복을 한다는 것입니다.
@list = ('ab','abc','bcd','def');
foreach $var (grep(/ab/,@list)){
$var = 1;
}
print (join(':',@list));
# perl4 의 출력: ab:abc:bcd:def
# perl5 의 출력: 1:1:bcd:def
perl4 처럼 하기에는, 자신이 임시 변수로 복사해서 그 배열에 대해서
반복을 수행합니다. 예를 들어,
foreach $var (grep(/ab/,@list)){
이 부분을 아래처럼 변경합니다.
foreach $var (@tmp = grep(/ab/,@list)){
그렇지 않으면, $var 를 변경한 때에 @list 의 값에 영향이 있습니다.
(이것은 루프 변수에
$_ 를 사용하고 있으며,
$_ 를 국소화하고 있지 않은
서브틴을 루프의 안에서 호출하는 때에 자주 발생합니다)
split with no args behavior changed
인수없는
split 행동은
split /\s+/ 때와
($_ 가 공백으로 시작되어있을 때에 앞의 필드가 공백이 됩니다)
같기에,
split ' ' 때와
($_ 가 공백으로 시작될 때에 앞의 필드가 공백이 되지 않습니다)
같은 것이 됩니다.
$_ = ' hi mom';
print join(':', split);
# perl4 の出力: :hi:mom
# perl5 の出力: hi:mom
-e behavior fixed
perl4 에서는,
-e 스위치로 접근한 텍스트는 무시되고, 항상
뒤에 따라온 인수부터 프로그램이 뽑아내었었습니다. 거기에,
-e 스위치의 뒤에 인수를 넘기지 않은 경우도 받아들였습니다.
이런 행동은 양쪽 모두 수정되었습니다.
perl -e'print "attached to -e"' 'print "separate arg"'
# perl4 의 출력: separate arg
# perl5 의 출력: attached to -e
perl -e
# perl4 prints:
# perl5 dies: No code specified for -e.
push returns number of elements in resulting list
perl4 에서는
push 의 반환값은 문서에 쓰여져 있지 않았지만,
실제로는 대상이 되는 리스트에 마지막에 push한 값dl 반환되었습니다.
Perl5 에서는,
push 의 반환값은 문서에 명기되었고 그것은,
perl4 부터 변경되었습니다. 이것은 push한 뒤의 리스트에 있는 요소의 수를
반환합니다.
@x = ('existing');
print push(@x, 'first new', 'second new');
# perl4 의 출력: second new
# perl5 의 출력: 3
Some error messages differ
일부의 에러메시지가 다릅니다.
split() honors subroutine args
Perl 4 에서는, 리스트컨텍스트에서
split() 의 최초의 인수의
구분자가
?? 였던 경우, 반환된 결과가
@_ 에도 설정되었습니다.
Perl 5에서는 서브루틴의 인수에 의해 많은 경의를 가집니다.
Bugs removed
몇개인가 버그가 수정되었을 지도 모릅니다
(파싱의 함정)
파싱에 관한 Perl4 와 Perl5 의 차이의 함정입니다.
$string . = "more string";
print $string;
# perl4 의 출력: more string
# perl5 의 출력: syntax error at - line 1, near ". ="
Better parsing in perl 5
perl5 에서는 구문해석이 개량되었습니다.
sub foo {}
&foo
print("hello, world\n");
# perl4 의 출력: hello, world
# perl5 의 출력: syntax error
Function parsing
``그것이 함수로 보이는 것이면, 그것은 함수다''라는 룰.
print
($foo == 1) ? "is one\n" : "is zero\n";
# perl4 의 출력: is zero
# perl5 의 경고: "Useless use of a constant in void context" if using -w
String interpolation of $#array differs
$#array 구조의 문자열전개로 이름의 주변에 프레이즈가 있을 때에는
차이가 있습니다.
@a = (1..3);
print "${#a}";
# perl4 prints: 2
# perl5 fails with syntax error
@ = (1..3);
print "$#{a}";
# perl4 prints: {a}
# perl5 prints: 2
Perl guesses on map, grep followed by { if it starts BLOCK or hash ref
perl 이
map { (또는
grep {) 를 발견하면,
{ 가 BLOCK 의 개시가
해쉬리퍼런스인가를 추측합니다.
추측에 실패하면,
} 의 근처에서 컴마가 없다(혹은 예상외의 위치에 컴마가 있다) 라는 에러가 보고됩니다.
Use unary
+ before
{ on a hash reference, and unary
+ applied
to the first thing in a BLOCK (after
{), for perl to guess right all
the time. (See
map in perlfunc.)
(TBT)
(숫자값의 함정)
같은 것에 대한 숫자연산자, 오퍼랜드, 출력에 관한
Perl 4와 Perl5 의 차이에 대한 함정입니다.
print 7.373504 - 0, "\n";
printf "%20.18f\n", 7.373504 - 0;
# Perl4 의 출력:
7.3750399999999996141
7.375039999999999614
# Perl5 의 출력:
7.373504
7.375039999999999614
Perl 5 에서는, 최초의 결과가 보다 좋은 것인 것에 주의해 주세요.
Your results may vary, since your floating point formatting routines
and even floating point format may be slightly different.
(TBT)
Auto-increment operator over signed int limit deleted
여기에 기술된 항목은 삭제되었습니다.
이전 있었던 것에서는, 오토인크리먼트 연산자가 등호붙은 정수의 한계를
넘은 것을 감지하지 않았던 것을 소개하고 있었습니다.
이것은 버젼 5.003_04 에서 수정되었습니다만, 큰 정수를 다루는 것에
불안한 느낌이 있다면
use Math::BigInt;
를 사용ㅏ는 것을 고려해주세요.
Assignment of return values from numeric equality tests doesn't work
숫자의 등가성의 비교의 결과를 대입해서도, perl 에서는 그 비교의 결과가
거짓(0) 이었던 때에는 잘 되지않습니다.
논리비교는 현재 0 가 아닌 null 을 반환합니다.
$p = ($test == 1);
print $p,"\n";
# perl4 의 출력: 0
# perl5 의 출력:
이런 새로운 스펙의 다른 예는
General Regular Expression Traps using s///, etc.를 참조해주세요.
Bitwise string ops
숫자값으로써도 문자열로써도 조작가능한 비트조작연산자 (
& | ^ ~) 가
문자열만을 인수로써 부여된 경우,
Perl 4에서는 프로그램이
vec() 함수의 호출을 포함하고 있으면 오퍼랜드를
비트문자열로써 취급합니다.
Perl 5는 문자열 오퍼랜드를 비트문자열로써 취급합니다.
(보다 자세한 내용에 대해서는
Bitwise String Operators in perlop 를 참조해주세요.)
$fred = "10";
$barney = "12";
$betty = $fred & $barney;
print "$betty\n";
# Uncomment the next line to change perl4's behavior
# ($dummy) = vec("dummy", 0, 0);
# Perl4 prints:
8
# Perl5 prints:
10
# If vec() is used anywhere in the program, both print:
10
(일반적인 데이터 형태의 함정)
대부분의 데이터 형태와, 그것들의 특정 표현이나 컨텍스트에서의
사용법에 관한 Perl4 와 Perl5 의 차이에 대한 함정입니다.
@a = (1, 2, 3, 4, 5);
print "The third element of the array is $a[3] also expressed as $a[-2] \n";
# perl4 의 출력: The third element of the array is 4 also expressed as
# perl5 의 출력: The third element of the array is 4 also expressed as 4
Setting $#array lower now discards array elements
$#array 에(그것보다도) 작은 값을 설정한 경우에는, 쓸데없는
배열요소를 버리고, 거기에 그것이 원래대로 돌아가지 않도록 합니다.
@a = (a,b,c,d,e);
print "Before: ",join('',@a);
$#a =1;
print ", After: ",join('',@a);
$#a =3;
print ", Recovered: ",join('',@a),"\n";
# perl4 의 출력: Before: abcde, After: ab, Recovered: abcd
# perl5 의 출력: Before: abcde, After: ab, Recovered: ab
Hashes get defined before use
해쉬는 사용되기 전에 정의됩니다.
local($s,@a,%h);
die "scalar \$s defined" if defined($s);
die "array \@a defined" if defined(@a);
die "hash \%h defined" if defined(%h);
# perl4 의 출력:
# perl5 dies: hash %h defined
Perl 은
defined(@a) 와
defined(%h) 에
경고를 내도록 되어있습니다.
Glob assignment from localized variable to variable
어떤 변수에서 별도의 변수로 GLOB 대입은
대입된 변수가 대입한 뒤에 국소화되어 있는 때에는
실패합니다.
@a = ("This is Perl 4");
*b = *a;
local(@a);
print @b,"\n";
# perl4 의 출력: This is Perl 4
# perl5 의 출력:
Assigning undef to glob
undef 의 GLOB 로의 대입은 Perl5 에서는 어떤 영향도 끼치지 않습니다.
Perl4 에서는 결합된 스칼라를 undef 합니다.
(그러나 SEGV 를 포함해, 뭔가의 부작용이 있을 지도 모릅니다).
Perl 5는 또 형태GLOB에
undef 를 대입하면 경고가 납니다.
(형태GLOB에
undef 를 대입하는 것은 형태GLOB에 대해
undef 함수를 호출하는 것과는 다릅니다). 몇 가지의 효과가 있습니다.
$foo = "bar";
*foo = undef;
print $foo;
# perl4 prints:
# perl4 warns: "Use of uninitialized variable" if using -w
# perl5 prints: bar
# perl5 warns: "Undefined value assigned to typeglob" if using -w
Changes in unary negation (of strings)
(문자열에 대한 당항의 부등반전의 의미가 변하였습니다.
이 변경은 반환값과 매직 인크리먼트의 양쪽에 양향이 있습니다.
$x = "aaa";
print ++$x," : ";
print -$x," : ";
print ++$x,"\n";
# perl4 の出力: aab : -0 : 1
# perl5 の出力: aab : -aab : aac
Modifying of constants prohibited
perl4 에서는 정수를 변경해 버립니다.
$foo = "x";
&mod($foo);
for ($x = 0; $x < 3; $x++) {
&mod("a");
}
sub mod {
print "before: $_[0]";
$_[0] = "m";
print " after: $_[0]\n";
}
# perl4:
# before: x after: m
# before: a after: m
# before: m after: m
# before: m after: m
# Perl5:
# before: x after: m
# Modification of a read-only value attempted at foo.pl line 12.
# before: a
defined $var behavior changed
perl4 와 perl5 에서는 전혀 다른 동작을 합니다:
print "$x", defined $x
# perl 4: 1
# perl 5: <no output, $x is not called into existence>
Variable Suicide
perl5 에서는, 변수의 자살(variable sucide) 행동은 보다
일관된 것이 됩니다.
perl4 에서는 스칼라만이 그런 비슷한 행동을,
perl5 에서는 해쉬와 스칼라에서 보입니다.
$aGlobal{ "aKey" } = "global value";
print "MAIN:", $aGlobal{"aKey"}, "\n";
$GlobalLevel = 0;
&test( *aGlobal );
sub test {
local( *theArgument ) = @_;
local( %aNewLocal ); # perl 4 != 5.001l,m
$aNewLocal{"aKey"} = "this should never appear";
print "SUB: ", $theArgument{"aKey"}, "\n";
$aNewLocal{"aKey"} = "level $GlobalLevel"; # 출력해야하는 것
$GlobalLevel++;
if( $GlobalLevel<4 ) {
&test( *aNewLocal );
}
}
# Perl4:
# MAIN:global value
# SUB: global value
# SUB: level 0
# SUB: level 1
# SUB: level 2
# Perl5:
# MAIN:global value
# SUB: global value
# SUB: this should never appear
# SUB: this should never appear
# SUB: this should never appear
(컨텍스트의 함정 - 스칼라 컨텍스트와 리스트컨텍스트)
@fmt = ("foo","bar","baz");
format STDOUT=
@<<<<< @||||| @>>>>>
@fmt;
.
write;
# perl4 errors: Please use commas to separate fields in file
# perl5 の出力: foo bar baz
caller() returns false value in scalar context if no caller present
caller() 함수는 호출하는 곳이 없고, 스칼라 컨텍스트에서 불러진 경우에는
거짓을 반환하도록 되었습니다. 이것에 의해 라이브러 파일이
(자신이) require 되었다는 것을 판단할 수 있습니다.
caller() ? (print "You rang?\n") : (print "Got a 0\n");
# perl4 errors: There is no caller
# perl5 의 출력: Got a 0
Comma operator in scalar context gives scalar context to args
스칼라 컨텍스트에 있는 컴마 연산자는, 그 인수애 대해
스칼라 컨텍스트를 주도록 되었습니다.
@y= ('a','b','c');
$x = (1, 2, @y);
print "x = $x\n";
# Perl4 prints: x = c # Thinks list context interpolates list
# Perl5 prints: x = 3 # Knows scalar uses length of list
sprintf() prototyped as ($;@)
sprintf() 의 프로토타입은 ($;@) 이기에, 최초의 인수는
스칼라컨텍스트입니다. 따라서, 배열을 넘기면,
Perl 4 와는 달리 아마도 당신이 바라지 않는 결과가 될 것입니다.
@z = ('%s%s', 'foo', 'bar');
$x = sprintf(@z);
print $x;
# perl4 prints: foobar
# perl5 prints: 3
그러나,
printf() 쪽은 Perl4 와 같은 행동을 합니다:
@z = ('%s%s', 'foo', 'bar');
printf STDOUT (@z);
# perl4 출력: foobar
# perl5 출력: foobar
(평가 순서의 함정)
평가순서에 관한 Perl4 와 Perl5 의 차이에 대한 함정입니다.
Perl4 는 대부분의 연산자에서 Perl5 처럼 우선순위를 가지고 있습니다.
그러나, Perl4 에서는, 문서와는 조금 다른 듯한 일관성에 결점이 있습니다.
@arr = ( 'left', 'right' );
$a{shift @arr} = shift @arr;
print join( ' ', keys %a );
# perl4 의 출력: left
# perl5 의 출력: right
Semantic errors introduced due to precedence
아래의 예는, 우선순위의 관계에서 의미에러(semantic error)가 되도록 했습니다.
@list = (1,2,3,4,5);
%map = ("a",1,"b",2,"c",3,"d",4);
$n = shift @list + 2; # 리스트의 최초의 요소에 2를 더한다.
print "n is $n, ";
$m = keys %map + 2; # 해쉬에 있는 아이템의 수+2
print "m is $m\n";
# perl4 출력: n is 3, m is 6
# perl5 errors and fails to compile
Precedence of assignment operators same as the precedence of assignment
대입연산자의 우선순위는, 대입과 같습니다.
perl4 는 달라서, 이 우선순위가 관련연산자와 같은 것으로 되어 있습니다.
이 때문에, 식의 안에 있는 것과 같도록 괄호로 감싸지 않으면
안되도록 되었습니다.
/foo/ ? ($a += 2) : ($a -= 2);
아래와 같이 해버리면,
/foo/ ? $a += 2 : $a -= 2
이것은
(/foo/ ? $a += 2 : $a) -= 2;
처럼 다르게 해석될 수 있습니다.
한편,
$a += /foo/ ? 1 : 2;
이것은 C 프로그래머가 기대하고 있을 동작이 됩니다.
open requires parentheses around filehandle
open FOO || die;
이것은 더이상 옳은 방법이 아닙니다. 여기에서는 파일핸들을
괄호로 감쌀 필요가 있습니다. 그렇지 않으면, perl5 는 이런 구문을
그 기본값의 우선순위 대로 놔둡니다(아래의 예를 참조하세요).
open(FOO || die);
# perl4 opens or dies
# perl5 opens FOO, dying only if 'FOO' is false, i.e. never
$: precedence over $:: gone
perl4 는 특수변수
$: 의 우선순위에, perl5 가
$:: 를 main 패키지로
보는 것과 같은 우선순위를 부여합니다.
$a = "x"; print "$::a";
# perl 4 의 출력: -:a
# perl 5 의 출력: x
Precedence of file test operators documented
perl 에는, 파일테스트 연산자와 대입연산자를 조합할 때에
우선순위의 버그가 있었습니다. 따라서, Perl4 의 우선순위 테이블에서는
-e $foo .= "q" 는
((-e $foo) .= "q") 로 해석되어야 하는 데 실제로는
((-e $foo) .= "q") 로 해석해 버립니다.
Perl5 에서는 문서에 있는 대로의 우선순위입니다.
-e $foo .= "q"
# perl4 の出力: no output
# perl5 の出力: Can't modify -e in concatenation
keys, each, values are regular named unary operators
perl4 에서는, key(), each(),
values() 는 싱글 해쉬에 대해
특별히 높은 평가순위를 가졌던 연산자 였습니다.
그러나 perl5 에선, 이런 연산자는 일반적인 이름붙은 단항연산자가 됩니다.
문서에 있는 대로, 이름붙은 단항연산자는,
+ - . 처럼
수학연산자나 연결연산자보다도 낮은 우선순위를 가지고 있습니다.
그러나 perl4 에서는 이런 연산자보다도
key() 들 쪽이 강력한 연산대상으로
보고 있었습니다.
따라서, 아래의 예제처럼 됩니다.
%foo = 1..10;
print keys %foo - 1
# perl4 prints: 4
# perl5 prints: Type of arg 1 to keys must be hash (not subtraction)
이 perl4 의 행동은 편리할지도 모릅니다만, 일관성에 문제가 있습니다.
(s/// 등을 사용할 때의 일반적인 정규표현의 함정)
정규표현에 관한 모든 타입의 함정.
$a=1;$b=2;
$string = '1 2 $a $b';
$string =~ s'$a'$b';
print $string,"\n";
# perl4 의 출력: $b 2 $a $b
# perl5 의 출력: 1 2 $a $b
m//g attaches its state to the searched string
m//g 는, 그 상태를 정규표현이 아닌 검색대상의 문자열로 보도록 했습니다.
(sub 에 대해 블록의 영역이 남아있다면, 검색문자열의 상태는 잃어버립니다).
$_ = "ababab";
while(m/ab/g){
&doit("blah");
}
sub doit{local($_) = shift; print "Got $_ "}
# perl4 prints: Got blah Got blah Got blah Got blah
# perl5 의 출력: infinite loop blah...
m//o used within an anonymous sub
현재,
m//o 양지정자를 이름없는 서브루틴의 안에 있는 정규표현에서
사용한 경우,
모든 클로져는 그런 이름없는 서브루틴에서,
그런 클로져의 안에서 제일 처음에 사용되는 것의 안에서
컴파일 되는 것처럼 정규표현을 생성합니다.
sub build_match {
my($left,$right) = @_;
return sub { $_[0] =~ /$left stuff $right/o; };
}
$good = build_match('foo','bar');
$bad = build_match('baz','blarch');
print $good->('foo stuff bar') ? "ok\n" : "not ok\n";
print $bad->('baz stuff blarch') ? "ok\n" : "not ok\n";
print $bad->('foo stuff bar') ? "not ok\n" : "ok\n";
For most builds of Perl5, this will print:
ok
not ok
not ok
이 예제의 경우,
build_match() 는 항상
최초에
build_match() 가 호출된 때의
$left와 $right 의 내용에 매치하는 서브루틴을 반환합니다.
호출된 그 시점에서의 값이 아닙니다.
$+ isn't set to whole match
매칭의 안에서 괄호가 사용되지 않은 경우, perl4 에서는
$+ 에는
$& 처럼 매치한 전체가 설정되지만,
Perl5 에서는 그렇지 않습니다.
"abcdef" =~ /b.*e/;
print "\$+ = $+\n";
# perl4 의 출력: bcde
# perl5 의 출력:
Substitution now returns null string if it fails
치환은 실패한 때엔는 빈 문자열을 반환하도록 되었습니다.
$string = "test";
$value = ($string =~ s/foo//);
print $value, "\n";
# perl4 의 출력: 0
# perl5 의 출력:
이 새로운 스펙에 관해서는
숫자값에 관한 함정 도 참조해주세요.
s`lhs`rhs` is now a normal substitution
s`lhs`rhs` (역 따옴표의 사용)은 보통 치환이 되고,
역따옴표의 전개는 수행되지 않습니다.
$string = "";
$string =~ s`^`hostname`;
print $string, "\n";
# perl4 의 출력: <the local hostname>
# perl5 의 출력: hostname
Stricter parsing of variables in regular expressions
정규표현 중의 변수의 사용에 관한 구문해석이 보다 엄밀하게 되었습니다.
s/^([^$grpc]*$grpc[$opt$plus$rep]?)//o;
# perl4: compiles w/o error
# perl5: with Scalar found where operator expected ..., near "$opt$plus"
같은 스크립트에서 이 예제에 부가한 것은,
치환 후의 문자열의 실제의 값입니다.
[$opt] 는 perl4 에서는 캐릭터클래스이고, perl5 에서는
배열의 첨자가 됩니다.
$grpc = 'a';
$opt = 'r';
$_ = 'bar';
s/^([^$grpc]*$grpc[$opt]?)/foo/;
print;
# perl4 의 출력: foo
# perl5 의 출력: foobar
m?x? matches only once
perl5 에서는
m?x? 나
?x? 처럼 한번만 매치합니다.
perl4 에서는
/x/ 나
m!x! 처럼 몇번이도 매치합니다.
$test = "once";
sub match { $test =~ m?once?; }
&match();
if( &match() ) {
# m?x? が2회 이상 매치
print "perl4\n";
} else {
# m?x? が한번만 매치
print "perl5\n";
}
# perl4 의 출력: perl4
# perl5 의 출력: perl5
Failed matches don't reset the match variables
Ruby 와는 달리, Perl 에서는 매칭에 실패해도 매칭 변수
($1, $2, ...,
$`, ...) 는 리셋되지 않습니다.
(서브루틴, 시그널, 정렬의 함정)
Perl4 와 Perl5 의 차이의 함정으로 분류된 일반적인 것은
시그널, 정렬, 그리고 그것들에 관련한 서브루틴으로, 몇가지의 OS 고유의
함정을 포함한 서브루틴의 함정과 같은 것입니다.
sub SeeYa { warn"Hasta la vista, baby!" }
$SIG{'TERM'} = SeeYa;
print "SIGTERM is now $SIG{'TERM'}\n";
# perl4 prints: SIGTERM is now main'SeeYa
# perl5 prints: SIGTERM is now main::1 (and warns "Hasta la vista, baby!")
-w 를 사용해서, 이것을 발견할 수 있습니다.
Reverse is no longer allowed as the name of a sort subroutine
reverse 는 더이상 정렬의 서브루틴의 이름으로써는 사용할 수 없게 되었습니다.
sub reverse{ print "yup "; $a <=> $b }
print sort reverse (2,1,3);
# perl4 prints: yup yup 123
# perl5 prints: 123
# perl5 warns (if using -w): Ambiguous call resolved as CORE::reverse()
warn() won't let you specify a filehandle.
항상 STDERR 에 출력하고 있던 것에 상관없이, perl4 에서는
warn() 은
파일핸들의 지정을 필요로 햇었습니다만, perl5에서는 필요없어졌습니다.
warn STDERR "Foo!";
# perl4 의 출력: Foo!
# perl5 의 출력: String found where operator expected
(OS 의 함정)
- SysV resets signal handler correctly
HPUX 및 일부의 SysV? OS 에서는, perl4 때에는
시그널이 발생할 때에 그 시그널핸들러 함수의 안에서
시그널 핸들러를 재설정하지 않으면 안되었습니다.
perl5 에서는, 이 재설정을 제대로 수행하게 되었습니다.
핸들러를 재설정하지 않는 다는 것에 의존한 프로그램은
다시 작업할 필요가 있습니다.
5.002 이후의 perl 에서는, SysV? 때에는 sigaction() 을 사용합니.
sub gotit {
print "Got @_... ";
}
$SIG{'INT'} = 'gotit';
$| = 1;
$pid = fork;
if ($pid) {
kill('INT', $pid);
sleep(1);
kill('INT', $pid);
} else {
while (1) {sleep(10);}
}
# perl4 (HPUX) prints: Got INT...
# perl5 (HPUX) prints: Got INT... Got INT...
SysV seek() appends correctly
SysV? OS 에서는, 추가모드(
>>)로 오픈한 파일에 대해
seek() 는
fopen() 매뉴얼페이지에 있게 바르게 동작하게 되었습니다.
예를들면, 추가 모드로 파일을 연 경우에는,
특히 파일핸들에 있는 정보를 덮어쓸 수는 없습니다.
open(TEST,">>seek.test");
$start = tell TEST;
foreach(1 .. 9){
print TEST "$_ ";
}
$end = tell TEST;
seek(TEST,$start,0);
print TEST "18 characters here";
# perl4 (solaris) seek.test has: 18 characters here
# perl5 (solaris) seek.test has: 1 2 3 4 5 6 7 8 9 18 characters here
(전개의 함정)
Perl4 와 Perl5 의 차이의 함정에는, 식과 구문, 컨텍스트등에 의한
전개에 관한 것이 있습니다.
print "To: someone@somewhere.com\n";
# perl < 5.6.1, error : In string, @somewhere now must be written as \@somewhere
# perl >= 5.6.1, warning : Possible unintended interpolation of @somewhere in string
Double-quoted strings may no longer end with an unescaped $
쌍따옴표로 감싸진 문자열에 이스케이프되지 않은 $ 로 종료하는 것이
없어졌습니다.
$foo = "foo$";
print "foo is $foo\n";
# perl4 prints: foo is foo$
# perl5 errors: Final $ should be \$ or $name
주의: perl5 는, $bar 의 끝에 있는 @에 대해서 ``에러가 되지 않습니다''
Arbitrary expressions are evaluated inside braces within double quotes
Perl 은 쌍따옴표 안에 있는 중괄호의 안쪽의 임의의 식을
평가하도록 되었습니다(일반적으로는,
$ 나
@ 에 이어서
열린 중괄호가 온 때입니다).
@www = "buz";
$foo = "foo";
$bar = "bar";
sub foo { return "bar" };
print "|@{w.w.w}|${main'foo}|";
# perl4 의 출력: |@{w.w.w}|foo|
# perl5 의 출력: |buz|bar|
use strict; 를 사용해서, perl5 에서의 이런 함정을 피할 수 있습니다.
$$x now tries to dereference $x
``this is $$x'' 는 프로세스 ID 를 전개하도록 되어 있습니다만,
지금은 $x 의 참조벗기기(dereference) 를 시험합니다.
그래도
$$ 자신은 지금도 제대로 동작합니다.
$s = "a reference";
$x = *s;
print "this is $$x\n";
# perl4 의 출력: this is XXXx (XXX 는 최근 프로세스ID)
# perl5 prints: this is a reference
Creation of hashes on the fly with eval "EXPR" requires protection
eval "EXPR" 을 사용한 그 곳(on the fly)에서의 해쉬의 생성은
해쉬의 이름을 지정하는
$ 가 보호되어 있든지, 혹은
양쪽의 카리브레이스가 보호되어 있는 것을 요구합니다.
양쪽의 카리브레이스가 보호되어 있는 경우에는, perl4 와
perl5 의 결과는 같습니다.
$hashname = "foobar";
$key = "baz";
$value = 1234;
eval "\$$hashname{'$key'} = q|$value|";
(defined($foobar{'baz'})) ? (print "Yup") : (print "Nope");
# perl4 의 출력: Yup
# perl5 의 출력: Nope
아래의 것을:
eval "\$$hashname{'$key'} = q|$value|";
다음처럼 변경하면:
eval "\$\$hashname{'$key'} = q|$value|";
결과는 이렇게 됩니다:
# perl4 의 출력: Nope
# perl5 의 출력: Yup
아래처럼 변경한 경우에는
eval "\$$hashname\{'$key'\} = q|$value|";
결과는 이렇게 됩니다.
# perl4 의 출력: Yup
# perl5 의 출력: Yup
# 이것은 양쪽의 버젼에서 같은 결과가 됩니다.
Bugs in earlier perl versions
앞의 버젼에 있었던 버그에 의존하고 있는 perl4 프로그램.
perl -e '$bar=q/not/; print "This is $foo{$bar} perl5"'
# perl4 의 출력: This is not perl5
# perl5 의 출력: This is perl5
Array and hash brackets during interpolation
전개중의 배열과 해쉬의 대괄호에 대해서도 주의할 필요가 있습니다.
print "$foo["
perl 4 prints: [
perl 5 prints: syntax error
print "$foo{"
perl 4 의 출력: {
perl 5 의 출력: syntax error
Perl 5 is expecting to find an index or key name following the respective
brackets, as well as an ending bracket of the appropriate type. In order
to mimic the behavior of Perl 4, you must escape the bracket like so.
(TBT)
print "$foo\[";
print "$foo\{";
Interpolation of \$$foo{bar}
마찬가지로,
\$$foo{bar} 에도 주의해주세요.
$foo = "baz";
print "\$$foo{bar}\n";
# perl4 prints: $baz{bar}
# perl5 의 출력: $
perl5 는 의존하지 않는
$foo{bar} 를 찾으러 가지만, perl4 는
$foo 를 ``baz'' 에 전개한 것만으로 만족합니다.
eval 에도 이것에 주의해주세요.
qq() string passed to eval will not find string terminator
eval 에
qq() 된 문자열을 넘길 경우
eval qq(
foreach \$y (keys %\$x\) {
\$count++;
}
);
# perl4 runs this ok
# perl5 prints: Can't find string terminator ")"
(DBM의 함정)
DBM에 관한 일반적인 함정.
dbmopen (%dbm, "file", undef);
print "ok\n";
# perl4 의 출력: ok
# perl5 의 출력: ok (IFF linked with -ldbm or -lndbm)
DBM exceeding limit on the key/value size will cause perl5 to exit immediately
key/value 의 크기에 관한 제한을 넘었을 때에 발생하는 에러에 의해,
perl5 에서는 즉시 프로그램에서 exit 합니다.
dbmopen(DB, "testdb",0600) || die "couldn't open db! $!";
$DB{'trap'} = "x" x 1024; # 대부분의 dbm/ndbm에는 너무 큰 값
print "YUP\n";
# perl4 의 출력
dbm store returned -1, errno 28, key "trap" at - line 3.
YUP
# perl5 의 출력
dbm store returned -1, errno 28, key "trap" at - line 3.
(미분류의 함정)
그외 전부.
sub foo {
$rc = do "./do.pl";
return 8;
}
print &foo, "\n";
이고, do.pl 이 아래와 같은 내용이었다고 하면,
return 3;
doit.pl 의 실행결과는 이렇게 됩니다.
# perl 4 의 출력: 3 (서브루틴에서 즉시 빠져나옵니다)
# perl 5 의 출력: 8
do 를
require 로 바꿔도 같은 동작이 됩니다.
split on empty string with LIMIT specified
(빈문자열에 LIMIT 를 지정해서
split 를 사용한 경우)
$string = '';
@list = split(/foo/, $string, 2)
Perl4 는 빈문자열을 가진 하나의 요소의 리스트를 반환하지만, Perl5 는
빈 리스트를 반환합니다.
항상, 버그로써 공식적으로 선언된 것이 있으면,
그것은 수정되어 없어졌을 겁니다.
voltar para o topo