Perl için ortak gotchas? [kapalı]

Perl gizli özellikleri sorusu en az bir yanıt bir özellik veya bir yanlış özellik olarak kabul edilebilir. Bu soruyu takip etmek mantıklı görünüyordu: Perl'de yaygın olmayan bariz hatalar nelerdir? İşe yaraması gereken şeyler, ama yapma.

cevapların nasıl yapılanacağı konusunda yönergeler vermeyeceğim, ya da bir gotcha olarak kabul edilmesi için "çok kolay" nedir, çünkü oylama bunun için.

cevap tablosu

'

Semantik / Dil Özellikleri

'

En İyi Uygulamalar

Meta-Cevaplar

Ayrıca bakınız: ASP.NET - ortak gotchas

75
tarihinde sordu Adam Bellaire 2008-10-03 16:50:08
kaynak

29 ответов

tek tırnak yerine kullanılabilir olması :: tanımlayıcılarda.

düşünün:

use strict;
print "$foo";        #-- Won't compile under use strict
print "$foo's fun!"; #-- Compiles just fine, refers to $foo::s

aşağıdaki soruna yol açar:

use strict;
my $name = "John";
print "$name's name is '$name'";
# prints:
#  name is 'John'

bunu önlemenin önerilen yolu, değişken adınızın etrafında parantez kullanmaktır:

print "${name}'s name is '$name'";
# John's name is 'John'

ve use warnings olarak tanımsız değişken $name::s

kullanımı hakkında anlatacağım beri
38
cevap Adam Bellaire 2009-02-13 15:20:47
kaynak

sözcüksel bir filehandle yazdırabilirsiniz: iyi.

print $out "hello, world\n";

sonra filehandles bir karma olması güzel olabilir fark:

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: $!";

şimdiye kadar, çok iyi. Şimdi bunları kullanmayı deneyin ve bir duruma göre bir veya diğer yazdırmak:

my $where = (frobnitz() == 10) ? 'ok' : 'fail';

print $out{$where} "it worked!\n"; # it didn't: compile time error

karma dereference bir çift kıvırcık sarmak zorunda:

print {$out{$where}} "it worked!\n"; # now it did

bu tamamen sezgisel olmayan bir davranıştır. Eğer sen bunu duymadım, ya da belgelerde okudum, kendi başınıza çözebileceğinizden şüpheliyim.

28
cevap dland 2008-10-03 18:25:00
kaynak

bu bir meta-cevaptır. Perl::Critic , perlcritic komutu ile komut satırından yükleyip çalıştırabileceğiniz veya (kodunuzu internet üzerinden göndermekten mutluluk duyarsanız ve seçeneklerinizi özelleştiremiyorsanız) Perl::Critic web sitesi .

Perl::Critic ayrıca Damian Conways Perl en iyi referanslar sağlar Sayfa numaraları da dahil olmak üzere kitap uygulamaları. Yani tüm kitabı okumak için çok tembel iseniz, Perl::Critic hala okuma gerektiğini bit söyleyebilirim.

27
cevap pjf 2008-10-04 04:45:50
kaynak

Perl'in DWİMmer, << (burada belge) notasyonu ile sözcüksel filehandles ile print kullanırken mücadele eder:

# 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

çözüm filehandle ve << arasında boşluk eklemek veya {} parantez içinde sararak filehandle belirsizleştirmek için dikkatli olmaktır:

print {$fh}<<EOT;
foo
EOT
18
cevap Michael Carman 2008-10-03 19:11:11
kaynak

perltrap manpage Türüne göre organize unwary için birçok tuzakları listeler.

17
cevap Michael Carman 2008-10-04 01:06:02
kaynak

en yaygın gotcha

farklı bir şey ile dosyalarınızı başlatmaktır
use strict;
use diagnostics;

pjf ekler: teşhis performans üzerinde önemli etkisi vardır uyarılmalıdır. Perldiag'i yüklemesi gerektiği için program başlatmayı yavaşlatır.pod ve birkaç hafta önce bleadperl'e kadar, regexps'i yavaşlatır ve şişer, çünkü $&kullanır. Uyarıların kullanılması ve sonuçlarda splain çalıştırılması önerilir.

16
cevap Vinko Vrsalovic 2017-05-23 14:55:01
kaynak

skalerlere diziler atama bana mantıklı gelmiyor. Örneğin:

$foo = ( 'a', 'b', 'c' );

,' C ' değerini $foo'ya atar ve dizinin geri kalanını atar. Bu garip:

@foo = ( 'a', 'b', 'c' );
$foo = @foo;

bu, ilk örnekle aynı şeyi yapması gerektiği gibi görünüyor , ancak bunun yerine $foo uzunluk @foo , $foo == 3 .

15
cevap Graeme Perrow 2008-10-03 16:59:04
kaynak

"benim" bildirimlerim,

değişkenlerinin listelerinde parantez kullanmalıdır
use strict;
my $a = 1;
mysub();
print "a is $a\n";

sub {
    my $b, $a;   # Gotcha!
    $a = 2;
}

yazdırır a 2 çünkü my bildirimi sadece $b ( $a sözü sadece bir şey yapmadı). Bunun "sıkı kullan" etkisi altında olsa bile uyarı olmadan gerçekleştiğini unutmayın.

"kullanım uyarıları" (veya-w bayrağı) eklemek, Perl deyimiyle işleri büyük ölçüde geliştirir parantez "benim" listemde eksik . Bu, daha önce de olduğu gibi, hem sıkı hem de sıkı pragmaların neden her zaman iyi bir fikir olduğunu gösterir.

15
cevap andy 2012-06-16 10:13:46
kaynak

birleştirme başlatılmamış değer kullanımı...

bu beni deli ediyor. Bir dizi değişkeni içeren bir baskınız var:

print "$label: $field1, $field2, $field3\n";

ve değişkenlerden biri undef dir . Bunu programınızda bir hata olarak görüyorsunuz - bu yüzden "sıkı" pragmayı kullanıyordunuz. Belki de veritabanı şemanız, beklemediğiniz bir alanda NULL'A izin verdi veya bir değişkeni başlatmayı unuttunuz. Ama tüm hata iletisi, bir birleştirme ( . ) işlemi sırasında başlatılmamış bir değerle karşılaşıldığını söyler. Sadece size, başlatılmamış değişkenin adı olduğunu söyleseydi!

Perl, herhangi bir nedenle hata mesajında değişken adını yazdırmak istemediğinden, bir kesme noktası ayarlayarak (hangi değişkenin undef olduğuna bakmak için) veya durumu kontrol etmek için kod ekleyerek izlemeyi bitirirsiniz. Çok sadece bir CGI komut dosyasında binlerce kez olduğunda can sıkıcı ve kolayca yeniden oluşturamazsınız.

15
cevap andy 2012-06-16 10:14:56
kaynak

: referanslar ve gerçek nesneler:

$a = [1,2,3,4];
print $a[0];

( $a->[0] (en iyi), $$a[0] , @{$a}[0] veya @$a[0] )

15
cevap Vinko Vrsalovic 2015-05-13 17:06:18
kaynak

Perl'in döngü operatörlerinin çoğu( foreach , map , grep ) otomatik olarak $_ lokalize ama while(<FH>) değil. Bu garip eylem-at-a-mesafe yol açabilir.

14
cevap Michael Carman 2008-10-06 18:03:06
kaynak

bunu bir kez yaptım:

my $object = new Some::Random::Class->new;

hata bulmak için yaşları aldı. Dolaylı yöntem sözdizimi eeevil dir .

12
cevap Dan 2008-10-03 19:26:02
kaynak
my $x = <>;
do { 
    next if $x !~ /TODO\s*[:-]/;
    ...
} while ( $x );

do bir döngü değildir. Sen next olamaz . Bir blok gerçekleştirmek için bir talimat.

ile aynı şey
$inc++ while <>;

, C dilleri ailesinde bir inşaat gibi görünmesine rağmen.

11
cevap Axeman 2015-08-07 17:43:55
kaynak

sabitleri yeniden tanımlanabilir. Bir sabiti yanlışlıkla yeniden tanımlamanın basit bir yolu, bir sabiti bir referans olarak tanımlamaktır.

 use constant FOO => { bar => 1 };
 ...
 my $hash = FOO;
 ...
 $hash->{bar} = 2;

şimdi FOO {bar => 2};

mod_perl kullanıyorsanız (en azından 1.3'te) modül yenilenene kadar yeni FOO değeri devam edecektir.

9
cevap cwhite 2008-10-04 03:57:55
kaynak

Unary eksi "foo" ile "-foo" oluşturur:

perl -le 'print -"foo" eq "-foo" ? "true" : "false"'

bu sadece ilk karakter /[_a-zA-Z]/ ile eşleşirse çalışır . İlk karakter "-" ise, ilk karakteri "+" olarak değiştirir ve ilk karakter "+" ise ilk karakteri "-" olarak değiştirir . İlk karakter /[^-+_a-zA-Z]/ ile eşleşirse, dizeyi bir sayıya dönüştürmeye çalışır ve sonucu ortadan kaldırır.

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
'

yukarıdaki kod

yazdırır
-foo
+foo
-foo
-0
-5

bu özellik çoğunlukla insanların

gibi şeyleri söylemelerine izin vermek için var
my %options = (
    -depth  => 5,
    -width  => 2,
    -height => 3,
);
8
cevap Chas. Owens 2009-09-03 18:09:12
kaynak

bu gotcha Perl 5.10'da düzeltildi-eğer şeyleri yükseltmeye alerjisi olmayan bir yerde çalışacak kadar şanslıysanız>: - (

Ben Validly sıfır olan değişkenden bahsediyorum. bildiğiniz gibi,

gibi cümlelerde beklenmedik sonuçlara neden olan
unless ($x) { ... }
$x ||= do { ... };

/ 5.10 //= veya tanımlı-veya işlecine sahiptir.

geçerli sıfır olduğunda bu özellikle sinsi kodunuz üretime geçmeden önce testte dikkate alınmayan bazı kenar koşullarından kaynaklanır...

8
cevap RET 2012-06-16 10:11:02
kaynak

aşağıdaki senaryoda @ _ ne gibi değerler beklersiniz?

sub foo { } 

# empty subroutine called in parameters

bar( foo(), "The second parameter." ) ;

bar :

undef, "The second parameter." 

ama @ _ sadece ikinci parametre içerir, en azından perl 5.88 ile test ederken.

7
cevap 2008-10-06 21:06:03
kaynak

bir değişkende depolanan regex desenli /o değiştiricisini kullanarak.

m/$pattern/o

, /o , $pattern nın değişmeyeceğine dair bir sözdür. Perl, regex'in şartlı olarak değişip değişmediğini ve yeniden derlemesini tanıyacak kadar akıllıdır, bu nedenle artık /o kullanmak için iyi bir neden yoktur. Alternatif olarak, qr// (örneğin Çek kaçınarak takıntılı iseniz) kullanabilirsiniz.

6
cevap Michael Carman 2008-10-04 00:40:30
kaynak

Graeme Perrow'un cevabı iyiydi, ama daha da iyi oluyor!

liste bağlamında güzel bir liste döndüren tipik bir işlev göz önüne alındığında, şu soruyu sorabilirsiniz: skaler bağlamında ne geri dönecek? ("Tipik" olarak, dokümantasyonun söylemediği ortak durum anlamına gelir ve herhangi bir wantarray komik iş kullanmadığını varsayarız. Belki de Kendin yazdığın bir işlevdir.)

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

bu işlevdeki return ifadelerine bir işlev çağrıldığında bağlam yayılır.

sanırım arayan kod davranışı hakkında verimli akıl yürütme etkinleştirmek için başparmak basit bir kural istemek yanlıştı . Haklısın, Perl, arayanın karakterinin her seferinde kaynak kodundan geçmesi daha iyi .

6
cevap j_random_hacker 2017-05-23 13:31:39
kaynak

== ve != yerine eq ve ne kullanarak dizeleri karşılaştırarak . Örneğin:

$x = "abc";
if ($x == "abc") {
    # do something
}

yerine:

$x = "abc";
if ($x eq "abc") {
    # do something
}
6
cevap Nathan Fellman 2009-12-06 15:40:18
kaynak

@array = split( / /, $string );

ile aynı sonucu vermez
@array = split( ' ', $string );

$string lider boşluk varsa?

bu sürpriz bazı insanlar alabilir.

6
cevap AmbroseChapel 2011-07-12 10:02:26
kaynak

tüm typeglob dışa sürece dışa aktarılan değişkenleri yerelleştiremezsiniz.

5
cevap Michael Carman 2008-10-03 17:15:12
kaynak

bunu yapacak kadar aptalsanız, Perl aynı ada sahip birden çok değişkeni bildirmenize izin verecektir:

my ($x, @x, %x);

Perl bağlam yerine değişken türü tanımlamak için sigils kullandığı için, bu neredeyse daha sonra kod $x bir referans ise, değişkenleri kullanır karışıklık garanti:

$x[0]
$x{key}
$x->[0]
$x->{key}
@x[0,1]
@x{'foo', 'bar'}
@$x[0,1]
@$x{'foo', 'bar'}
...
4
cevap Michael Carman 2008-10-03 19:24:58
kaynak

ekstra parantez eklemek asla kodun anlamını değiştiremez , değil mi? Doğru mu?

my @x = ( "A"  x 5 );      # @x contains 1 element, "AAAAA"
my @y = (("A") x 5 );      # @y contains 5 elements: "A", "A", "A", "A", "A"

oh, bu doğru, bu Perl.

Düzenle: sadece iyi bir önlem için, x skaler bağlamında çağrılırsa, parantezler sonuçta önemli değildir:

my $z = ( "A"  x 5 );      # $z contains "AAAAA"
my $w = (("A") x 5 );      # $w contains "AAAAA" too

sezgisel.

4
cevap j_random_hacker 2009-02-15 16:34:38
kaynak

, bu sonuçlar üzerinde testler yapmadan önce readdir sonuçlarına dizin yolunu ön plana çıkarmayı unutuyor. İşte bir örnek:

#!/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...

bu gotcha, readdir belgelerinde belirtilmiştir, ancak yine de oldukça yaygın bir hata olduğunu düşünüyorum.

3
cevap Telemachus 2009-06-24 14:05:05
kaynak

karma "oluşturucu" bir listeden başka bir şey değildir ve => FAT virgül sözdizimsel şekerden başka bir şey değildir. [] arrayref sözdizimini () liste sözdizimiyle karıştırırken bu şekilde ısırılabilirsiniz:

my %var = (
    ("bar", "baz"),
    fred => "barney",
    foo => (42, 95, 22)
);

# result
{ 'bar' => 'baz',
  '95' => 22,
  'foo' => 42,
  'fred' => 'barney' };

# wanted
{ 'foo' => [ 42, 95, 22 ] }
1
cevap hhaamu 2011-08-15 21:16:46
kaynak

değişken adları yanlış yazım ... Bir zamanlar Perl'de bir hata değil, daha ziyade yeni bir değişkenin beyanı olan bir değişken adına bir yazım hatası bulmak için doğru davranmayan bir öğleden sonra sorun giderme kodunu geçirdim.

-1
cevap paxos1977 2008-10-04 04:08:24
kaynak

bir for(her biri) 'de döngü yaptığınız diziyi aşağıdaki gibi değiştirin:

my @array = qw/a b c d e f g h/;

for ( @array ) {
    my $val = shift @array;
    print $val, "\n";
}

kafası karışıyor ve

beklediğiniz şeyi yapmıyor
-2
cevap Matteo Riva 2010-01-06 23:08:19
kaynak

bir skaleri bir tamsayı olarak tedavi eder:

$n = 1729;
$s = 0;
$i = 0;

while ($n) {
    $s += $n % 10;
    $n/=10;
    $i ++
}

print "Sum : $s\n";
print "Number of iterations : $i\n"

toplam: 19

yineleme sayısı: 327

ideal olarak sadece dört yineleme olmalıydı, ancak bir skaler bir int değil ve beklenmedik bir sonuç aldık.

-2
cevap Balbir Singh 2012-06-16 10:16:49
kaynak

Diğer sorular perl