Perl의 일반적인 문제?
Perl의 숨겨진 기능에 대한 질문 은 기능 또는 잘못된 기능으로 간주 될 수있는 적어도 하나의 응답 을 산출했습니다 . 이 질문에 대한 후속 조치는 논리적으로 보였습니다. Perl에서 흔히 발생하는 분명하지 않은 실수는 무엇입니까? 작동해야하는 것처럼 보이지만 작동하지 않는 것.
나는 답변을 구성하는 방법에 대한 지침을 제공하지 않을 것입니다. 그것이 투표의 목적이기 때문입니다.
답변 표
통사론
- 일반
- 파일 핸들
의미 / 언어 기능
- 일반
- 문맥
- 변수
디버깅
모범 사례
use strict
및use warnings
(또는use diagnostics
) 잊어 버림- 잘못된 변수 이름 (예 :
use strict
다시)
메타 답변
참조 : ASP.NET-일반적인 문제
작은 따옴표를 사용하여 식별자에서 ::를 대체 할 수 있습니다.
중히 여기다:
use strict;
print "$foo"; #-- Won't compile under use strict
print "$foo's fun!"; #-- Compiles just fine, refers to $foo::s
다음과 같은 문제가 발생합니다.
use strict;
my $name = "John";
print "$name's name is '$name'";
# prints:
# name is 'John'
이를 방지하는 권장 방법은 변수 이름 주위에 중괄호를 사용하는 것입니다.
print "${name}'s name is '$name'";
# John's name is 'John'
또한 use warnings
정의되지 않은 변수의 사용에 대해 알려줄 것이므로$name::s
어휘 파일 핸들로 인쇄 할 수 있습니다.
print $out "hello, world\n";
그런 다음 파일 핸들의 해시를 갖는 것이 좋을 수 있음을 알게됩니다.
my %out;
open $out{ok}, '>', 'ok.txt' or die "Could not open ok.txt for output: $!";
open $out{fail}, '>', 'fail.txt' or die "Could not open fail.txt for output: $!";
여태까지는 그런대로 잘됐다. 이제 그들을 사용하고 조건에 따라 하나 또는 다른 하나에 인쇄하십시오.
my $where = (frobnitz() == 10) ? 'ok' : 'fail';
print $out{$where} "it worked!\n"; # it didn't: compile time error
해시 역 참조를 한 쌍의 컬리로 래핑해야합니다.
print {$out{$where}} "it worked!\n"; # now it did
이것은 전혀 직관적이지 않은 행동입니다. 이것에 대해 듣지 못했거나 문서에서 읽었다면 스스로 알아낼 수 있을지 의심 스럽습니다.
이것은 메타 답변입니다. 불쾌한 개는 많은이에 의해 잡힌 펄 :: 평론가 설치 및 사용하여 명령 줄에서 실행할 수 있습니다 perlcritic
(명령, 또는 만약 당신이있는 거 옵션을 사용자 정의 할 수 없습니다 인터넷을 통해 코드를 보내 드리겠습니다 ) Perl :: Critic 웹 사이트 를 통해 .
Perl::Critic
페이지 번호를 포함 하여 Damian Conways Perl Best Practices 책에 대한 참조도 제공 합니다. 당신이 전체 책을 읽고 너무 게으른 경우에 그래서, Perl::Critic
여전히 당신이 비트 말할 수 있어야 읽을 수 있습니다.
Perl의 DWIMmer 는 어휘 파일 핸들과 함께 <<
사용할 때 (here-document) 표기법으로 어려움을 겪습니다 print
.
# here-doc
print $fh <<EOT;
foo
EOT
# here-doc, no interpolation
print $fh <<'EOT';
foo
EOT
# bitshift, syntax error
# Bareword "EOT" not allowed while "strict subs" in use
print $fh<<EOT;
foo
EOT
# bitshift, fatal error
# Argument "EOT" isn't numeric...
# Can't locate object method "foo" via package "EOT"...
print $fh<<'EOT';
foo
EOT
해결책은 파일 핸들과 사이에 공백을 포함 시키 <<
거나 파일 핸들을 {}
중괄호 로 감싸서 명확하게 만드는 것입니다 .
print {$fh}<<EOT;
foo
EOT
perltrap의 유형별로 구성 부주의에 대한 맨 페이지 목록은 많은 함정.
가장 일반적인 문제는 다음과 다른 것으로 파일을 시작하는 것입니다.
use strict;
use diagnostics;
pjf 는 다음을 추가합니다. 진단은 성능에 상당한 영향을 미칩니다. perldiag.pod를로드해야하기 때문에 프로그램 시작 속도가 느려지고 몇 주 전부터 bleadperl까지 $ &를 사용하기 때문에 regexps도 느려지고 부풀립니다. 경고를 사용 splain
하고 결과를 실행 하는 것이 좋습니다.
스칼라에 배열을 할당하는 것은 나에게 의미가 없습니다. 예를 들면 :
$foo = ( 'a', 'b', 'c' );
$ foo에 'c'를 할당하고 나머지 배열을 버립니다. 이것은 더 이상합니다.
@foo = ( 'a', 'b', 'c' );
$foo = @foo;
이 모습은 첫 번째 예제와 같은 일을해야 좋아하지만, 대신에이 설정 $foo
받는 길이 의 @foo
그래서 $foo == 3
.
"my"선언은 변수 목록을 괄호로 묶어야합니다.
use strict;
my $a = 1;
mysub();
print "a is $a\n";
sub {
my $b, $a; # Gotcha!
$a = 2;
}
선언이에만 적용 되었기 때문에 a is 2를 인쇄 합니다 ( 해당 행에 대한 언급은 아무 것도하지 않음). "use strict"가 적용되는 경우에도 경고없이 발생합니다.my
$b
$a
"경고 사용"(또는 -w 플래그)을 추가하면 Perl 이 "내"목록 주위에 괄호가 누락되어있는 상황이 크게 개선 됩니다 . 이것은 많은 사람들이 이미 알고 있듯이 엄격한 pragma와 경고 pragma가 항상 좋은 생각 인 이유를 보여줍니다.
연결에 초기화되지 않은 값 사용 ...
이것은 나를 미치게 만든다. 다음과 같은 여러 변수가 포함 된 인쇄물이 있습니다.
print "$label: $field1, $field2, $field3\n";
그리고 변수 중 하나는 undef 입니다. 여러분은 이것을 프로그램의 버그라고 생각합니다. 이것이 "strict"pragma를 사용하는 이유입니다. 데이터베이스 스키마가 예상하지 못한 필드에 NULL을 허용했거나 변수를 초기화하는 것을 잊었을 수 있습니다. 그러나 모든 오류 메시지는 연결 ( .
) 작업 중에 초기화되지 않은 값이 발견되었다는 것을 알려줍니다 . 초기화되지 않은 변수 의 이름 만 알려 주면 !
Perl은 어떤 이유로 오류 메시지에 변수 이름을 인쇄하지 않기 때문에 중단 점을 설정하거나 (어떤 변수가 undef 인지 확인하기 위해) 조건을 확인하는 코드를 추가하여 추적하게됩니다 . CGI 스크립트에서 수천 개 중 한 번만 발생하고 쉽게 다시 만들 수 없을 때 매우 짜증납니다.
혼란스러운 참조와 실제 객체 :
$a = [1,2,3,4];
print $a[0];
( $a->[0]
(best) $$a[0]
, @{$a}[0]
또는 @$a[0]
) 중 하나 여야합니다.
펄의 반복 사업자의 대부분은 ( foreach
, map
, grep
) 자동으로 지역화 $_
하지만 while(<FH>)
하지 않습니다. 이로 인해 원거리에서 이상한 행동이 발생할 수 있습니다.
나는 이것을 한 번했다 :
my $object = new Some::Random::Class->new;
오류를 찾기 위해 나이 가 들었습니다 . 간접 메서드 구문은 eeevil 입니다.
my $x = <>;
do {
next if $x !~ /TODO\s*[:-]/;
...
} while ( $x );
do
루프가 아닙니다. 당신은 할 수 없습니다 next
. 블록을 수행하라는 명령입니다. 그것은
$inc++ while <>;
그럼에도 불구하고 C 언어 계열의 구조처럼 보입니다.
상수를 재정의 할 수 있습니다. 실수로 상수를 재정의하는 간단한 방법은 상수를 참조로 정의하는 것입니다.
use constant FOO => { bar => 1 };
...
my $hash = FOO;
...
$hash->{bar} = 2;
이제 FOO는 {bar => 2}입니다.
mod_perl (최소 1.3 버전)을 사용하는 경우 모듈이 새로 고쳐질 때까지 새 FOO 값이 유지됩니다.
다음을 "foo"
생성하는 단항 마이너스 "-foo"
:
perl -le 'print -"foo" eq "-foo" ? "true" : "false"'
이것은 첫 번째 문자가 일치하는 경우에만 작동합니다 /[_a-zA-Z]/
. 첫 번째 문자가 a "-"
이면 첫 번째 문자를 a 로 변경하고 첫 "+"
번째 문자가 a "+"
이면 첫 번째 문자를 a로 변경합니다 "-"
. 첫 번째 문자가 일치 /[^-+_a-zA-Z]/
하면 문자열을 숫자로 변환하고 결과를 부정합니다.
perl -le '
print -"foo";
print -"-foo";
print -"+foo";
print -"\x{e9}"; #e acute is not in the accepted range
print -"5foo"; #same thing for 5
'
위의 코드가 인쇄됩니다.
-foo
+foo
-foo
-0
-5
이 기능은 대부분 사람들이
my %options = (
-depth => 5,
-width => 2,
-height => 3,
);
이 문제는 Perl 5.10에서 수정되었습니다. 업그레이드에 알레르기가없는 곳에서 일할 수있을만큼 운이 좋다면> :-(
나는 유효하게 0 인 변수에 대해 이야기 합니다. 다음과 같은 절에서 예기치 않은 결과를 초래하는 원인이 있습니다.
unless ($x) { ... }
$x ||= do { ... };
Perl 5.10에는 // = 또는 defined-or 연산자가 있습니다.
코드가 프로덕션으로 이동하기 전에 테스트에서 고려되지 않은 일부 에지 조건으로 인해 유효한 0이 발생하는 경우 특히 교활합니다.
다음 시나리오에서 @_ 에 어떤 값이 포함될 것으로 예상 합니까?
sub foo { }
# empty subroutine called in parameters
bar( foo(), "The second parameter." ) ;
나는 바 에서받을 것으로 예상 할 것이다 :
undef, "The second parameter."
그러나 @_ 는 적어도 perl 5.88로 테스트 할 때 두 번째 매개 변수 만 포함합니다.
/o
변수에 저장된 정규식 패턴과 함께 수정자를 사용합니다 .
m/$pattern/o
지정 /o
은 $pattern
변경되지 않는 약속입니다 . Perl은 변경 여부를 인식하고 조건부로 정규식을 다시 컴파일 할만큼 똑똑하므로 /o
더 이상 사용할 이유가 없습니다. 또는 사용할 수 있습니다 qr//
(예 : 수표를 피하는 데 집착하는 경우).
Graeme Perrow의 대답 은 좋았지 만 더 좋아졌습니다!
목록 컨텍스트에서 멋진 목록을 반환하는 일반적인 함수가 주어지면 다음과 같이 질문 할 수 있습니다. 스칼라 컨텍스트에서 무엇을 반환할까요? ( "전형적"이라는 말은 문서에 언급되지 않은 일반적인 경우를 의미하며 우리는 그것이 wantarray
재미있는 사업을 사용하지 않는다고 가정합니다 . 아마도 그것은 당신이 직접 작성한 함수일 것입니다.)
sub f { return ('a', 'b', 'c'); }
sub g { my @x = ('a', 'b', 'c'); return @x; }
my $x = f(); # $x is now 'c'
my $y = g(); # $y is now 3
함수가 호출 된 컨텍스트는 return
해당 함수의 명령문으로 전파됩니다 .
나는 호출자가 코드 동작에 대한 효율적인 추론을 가능하게 하기 위해 간단한 경험 법칙 을 원하는 것이 잘못되었다고 생각한다 . 당신 말이 맞아요, Perl, 호출자의 캐릭터가 매번 호출 된 함수의 소스 코드를 훑어 보는 것이 낫 습니다 .
사용하여 문자열 비교 ==
하고 !=
대신 eq
과 ne
. 예를 들면 :
$x = "abc";
if ($x == "abc") {
# do something
}
대신에:
$x = "abc";
if ($x eq "abc") {
# do something
}
사실은 어떻습니까
@array = split( / /, $string );
같은 결과를주지 않습니다
@array = split( ' ', $string );
$ string에 선행 공백이 있으면?
그것은 일부 사람들을 놀라게 할 수도 있습니다.
전체 typeglob을 내 보내지 않는 한 내 보낸 변수를 현지화 할 수 없습니다.
그렇게 할만큼 어리 석다면 Perl은 같은 이름으로 여러 변수를 선언 할 수 있습니다.
my ($x, @x, %x);
Perl은 변수 유형 이 아닌 컨텍스트 를 식별하기 위해시길을 사용하기 때문에 나중에 코드에서 변수를 사용할 때 특히 가 참조 인 경우 혼동을 거의 보장합니다 .$x
$x[0]
$x{key}
$x->[0]
$x->{key}
@x[0,1]
@x{'foo', 'bar'}
@$x[0,1]
@$x{'foo', 'bar'}
...
추가 괄호를 추가 하면 코드의 의미를 변경할 수 없습니다 . 권리?
my @x = ( "A" x 5 ); # @x contains 1 element, "AAAAA"
my @y = (("A") x 5 ); # @y contains 5 elements: "A", "A", "A", "A", "A"
아, 맞습니다. 이쪽은 펄입니다.
EDIT: Just for good measure, if x
is being called in scalar context, then the parentheses don't matter after all:
my $z = ( "A" x 5 ); # $z contains "AAAAA"
my $w = (("A") x 5 ); # $w contains "AAAAA" too
Intuitive.
Forgetting to prepend the directory path to the results of readdir
before doing tests on those results. Here's an example:
#!/usr/bin/env perl
use strict;
use warnings;
opendir my $dh, '/path/to/directory/of/interest'
or die "Can't open '/path/to/directory/of/interest for reading: [$!]";
my @files = readdir $dh; # Bad in many cases; see below
# my @files = map { "/path/to/directory/of/interest/$_" } readdir $dh;
closedir $dh or die "Can't close /path/to/directory/of/interest: [$!]";
for my $item (@files) {
print "File: $item\n" if -f $item;
# Nothing happens. No files? That's odd...
}
# Scratching head...let's see...
use Data::Dumper;
print Dumper @files;
# Whoops, there it is...
This gotcha is mentioned in the documentation for readdir
, but I think it's still a pretty common mistake.
The hash "constructor" is nothing more than a list, and the =>
fat comma is nothing more than syntactic sugar. You can get bitten by this when confusing the []
arrayref syntax with the ()
list syntax:
my %var = (
("bar", "baz"),
fred => "barney",
foo => (42, 95, 22)
);
# result
{ 'bar' => 'baz',
'95' => 22,
'foo' => 42,
'fred' => 'barney' };
# wanted
{ 'foo' => [ 42, 95, 22 ] }
Misspelling variable names... I once spent an entire afternoon troubleshooting code that wasn't behaving correctly only to find a typo on a variable name, which is not an error in Perl, but rather the declaration of a new variable.
Modifying the array you're looping on in a for(each) as in:
my @array = qw/a b c d e f g h/;
for ( @array ) {
my $val = shift @array;
print $val, "\n";
}
it gets confused and doesn't do what you would expect
Treating a scalar as an integer:
$n = 1729;
$s = 0;
$i = 0;
while ($n) {
$s += $n % 10;
$n/=10;
$i ++
}
print "Sum : $s\n";
print "Number of iterations : $i\n"
Sum : 19
Number of iterations : 327
Ideally it should have had only four iterations, but a scalar is not an int, and we got an unexpected result.
참고URL : https://stackoverflow.com/questions/166653/common-gotchas-for-perl
'Nice programing' 카테고리의 다른 글
MySQL 매개 변수화 된 쿼리 (0) | 2020.10.17 |
---|---|
DialogFragment 너비를 Fill_Parent로 만드는 방법 (0) | 2020.10.17 |
PreferenceScreen의 TimePicker (0) | 2020.10.17 |
Java 사용자가 자주 예외를 조용히 사용하는 이유는 무엇입니까? (0) | 2020.10.17 |
디렉토리에 대한“401 Unauthorized” (0) | 2020.10.17 |