Często widzisz sprawdzanie zdefiniowania, więc nie musisz zajmować się ostrzeżeniem o używaniu wartości undef (aw Perlu 5.10 mówi ona o niewłaściwej zmiennej):
Use of uninitialized value $name in ...
Tak więc, aby obejść to ostrzeżenie, ludzie wymyślają różnego rodzaju kod, który zaczyna wyglądać jak ważna część rozwiązania, a nie jak guma balonowa i taśma klejąca. Czasami lepiej jest pokazać, co robisz, wyraźnie wyłączając ostrzeżenie, którego próbujesz uniknąć:
{
no warnings 'uninitialized';
if( length $name ) {
...
}
}
W innych przypadkach użyj wartości null zamiast danych. Za pomocą operatora zdefiniowanego lub w Perlu 5.10 możesz podać length
jawny pusty ciąg (zdefiniowany i zwrócić zerową długość) zamiast zmiennej, która wyzwoli ostrzeżenie:
use 5.010;
if( length( $name // '' ) ) {
...
}
W Perlu 5.12 jest to trochę łatwiejsze, ponieważ length
na niezdefiniowanej wartości również zwraca undefined . Może się to wydawać trochę głupie, ale to podoba się matematykowi, którym chciałbym być. To nie powoduje ostrzeżenia, co jest powodem, dla którego istnieje to pytanie.
use 5.012;
use warnings;
my $name;
if( length $name ) {
...
}
length undef
zwraca undef, zamiast ostrzeżenia i zwracania 0. W kontekście logicznym undef jest tak samo fałszywe jak 0, więc jeśli celujesz w wersję 5.12 lub nowszą, możesz po prostu napisaćif (length $name) { ... }
Jak wskazuje mobrule, zamiast niewielkich oszczędności można użyć następujących rozwiązań:
if (defined $name && $name ne '') { # do something with $name }
Możesz zrezygnować ze zdefiniowanego czeku i dostać coś jeszcze krótszego, np .:
if ($name ne '') { # do something with $name }
Ale w przypadku, gdy
$name
nie jest zdefiniowane, chociaż przepływ logiczny będzie działał zgodnie z zamierzeniami, jeśli używaszwarnings
(a powinieneś), otrzymasz następujące ostrzeżenie:Tak więc, jeśli istnieje szansa, która
$name
może nie zostać zdefiniowana, naprawdę musisz przede wszystkim sprawdzić zdefiniowanie, aby uniknąć tego ostrzeżenia. Jak wskazuje Sinan Ünür, możesz użyć Scalar :: MoreUtils, aby uzyskać kod, który robi dokładnie to (sprawdza zdefiniowanie, a następnie sprawdza zerową długość) po wyjęciu z pudełka, za pomocąempty()
metody:use Scalar::MoreUtils qw(empty); if(not empty($name)) { # do something with $name }
źródło
Po pierwsze, ponieważ
length
zawsze zwraca liczbę nieujemną,if ( length $name )
i
if ( length $name > 0 )
są równoważne.
Jeśli nie masz nic przeciwko zamianie niezdefiniowanej wartości na pusty ciąg, możesz użyć
//=
operatora Perl 5.10, który przypisuje RHS do LHS, chyba że LHS jest zdefiniowany:#!/usr/bin/perl use feature qw( say ); use strict; use warnings; my $name; say 'nonempty' if length($name //= ''); say "'$name'";
Zwróć uwagę na brak ostrzeżeń o niezainicjowanej zmiennej, ponieważ
$name
przypisywany jest pusty ciąg, jeśli jest niezdefiniowany.Jeśli jednak nie chcesz polegać na instalacji 5.10, użyj funkcji dostarczonych przez Scalar :: MoreUtils . Na przykład powyższe można zapisać jako:
#!/usr/bin/perl use strict; use warnings; use Scalar::MoreUtils qw( define ); my $name; print "nonempty\n" if length($name = define $name); print "'$name'\n";
Jeśli nie chcesz bić
$name
, użyjdefault
.źródło
length( $name // '' )
.//
i//=
są prawdopodobnie najbardziej użytecznymi spośród istniejących operatorów wyspecjalizowanych.length
można teraz zwrócić coś, co nie jest liczbą (ale nie NaN;)W przypadkach, w których nie obchodzi mnie, czy zmienna jest
undef
równa lub równa''
, zwykle podsumowuję to jako:$name = "" unless defined $name; if($name ne '') { # do something with $name }
źródło
$name //= "";
czego właśnie napisał Sinan.$name ||= "";
undef
a""
, powinna po prostu zmienić jedno na drugie i użyć jednego testu. To nie zadziała w ogólnym przypadku, dla którego inne opublikowane rozwiązania są znacznie lepsze, ale w tym konkretnym przypadku prowadzi do zgrabnego kodu. Czy powinienem przeformułować moją odpowiedź, aby była jaśniejsza?Można powiedzieć
$name ne ""
zamiast
length $name > 0
źródło
Nie zawsze jest możliwe robienie powtarzalnych rzeczy w prosty i elegancki sposób.
Po prostu rób to, co zawsze robisz, gdy masz wspólny kod, który jest replikowany w wielu projektach:
Wyszukaj CPAN, ktoś może już mieć dla Ciebie kod. W tym numerze znalazłem Scalar :: MoreUtils .
Jeśli nie znajdziesz czegoś, co ci się podoba w CPAN, utwórz moduł i umieść kod w podprogramie:
package My::String::Util; use strict; use warnings; our @ISA = qw( Exporter ); our @EXPORT = (); our @EXPORT_OK = qw( is_nonempty); use Carp qw(croak); sub is_nonempty ($) { croak "is_nonempty() requires an argument" unless @_ == 1; no warnings 'uninitialized'; return( defined $_[0] and length $_[0] != 0 ); } 1; =head1 BOILERPLATE POD blah blah blah =head3 is_nonempty Returns true if the argument is defined and has non-zero length. More boilerplate POD. =cut
Następnie w swoim kodzie nazwij to:
use My::String::Util qw( is_nonempty ); if ( is_nonempty $name ) { # do something with $name }
Lub jeśli sprzeciwiasz się prototypom i nie sprzeciwiasz się dodatkowym parom, pomiń prototyp w module i wywołaj go w ten sposób:
is_nonempty($name)
.źródło
Scalar::MoreUtils
.&
sigila podczas wywoływania funkcji. Dlatego nie polegam na prototypach, aby wykonać całą pracę. Przypuszczam, że mógłbym dodać „i zakończyć używanie & sigil w wywołaniach podrzędnych, chyba że naprawdę masz to na myśli” do komunikatu o błędzie.Doskonała biblioteka Type :: Tiny zapewnia strukturę, za pomocą której można wbudować funkcję sprawdzania typów w kodzie Perla. To, co tutaj pokazuję, to tylko najcieńszy wierzchołek góry lodowej i używa Type :: Tiny w najbardziej uproszczony i ręczny sposób.
Aby uzyskać więcej informacji, zapoznaj się z Type :: Tiny :: Manual .
use Types::Common::String qw< NonEmptyStr >; if ( NonEmptyStr->check($name) ) { # Do something here. } NonEmptyStr->($name); # Throw an exception if validation fails
źródło
Co powiesz na
if (length ($name || '')) { # do something with $name }
Nie jest to w pełni równoważne z wersją oryginalną, ponieważ zwróci również fałsz, jeśli
$name
będzie wartością liczbową 0 lub ciągiem'0'
, ale będzie zachowywać się tak samo we wszystkich innych przypadkach.W perlu 5.10 (lub nowszym) właściwym podejściem byłoby użycie operatora zdefiniowanego lub zamiast:
use feature ':5.10'; if (length ($name // '')) { # do something with $name }
To zadecyduje, jaką długość otrzymać w oparciu o
$name
to, czy jest zdefiniowana, a nie czy to prawda, więc 0 /'0'
będzie poprawnie obsługiwać te przypadki, ale wymaga nowszej wersji perla niż wiele osób jest dostępnych.źródło
źródło