English 中文(简体)
When is it OK to use an undefined variable in perl with warnings enabled?
原标题:

With warnings enabled, perl usually prints Use of uninitialized value $foo if $foo is used in an expression and hasn t been assigned a value, but in some cases it s OK, and the variable is treated as false, 0, or without a warning.

What are the cases where an uninitialized/undefined variable can be used without a warning?

最佳回答

Summary

  • Boolean tests
  • Incrementing or decrementing an undefined value
  • Appending to an undefined value
  • Autovivification
  • Other mutators

Boolean tests

According to the perlsyn documentation,

The number 0, the strings 0 and , the empty list (), and undef are all false in a boolean context. All other values are true.

Because the undefined value is false, the following program

#! /usr/bin/perl

use warnings;

my $var;
print "A
" if $var;
$var && print "B
";
$var and print "C
";
print "D
" if !$var;
print "E
" if not $var;
$var or print "F
";
$var || print "G
";

outputs D through G with no warnings.

Incrementing or decrementing an undefined value

There s no need to explicitly initialize a scalar to zero if your code will increment or decrement it at least once:

#! /usr/bin/perl

use warnings;

my $i;
++$i while "aaba" =~ /a/g;
print $i, "
";

The code above outputs 3 with no warnings.

Appending to an undefined value

Similar to the implicit zero, there s no need to explicitly initialize scalars to the empty string if you ll append to it at least once:

#! /usr/bin/perl

use warnings;
use strict;

my $str;
for (<*>) {
  $str .= substr $_, 0, 1;
}
print $str, "
";

Autovivification

One example is "autovivification." From the Wikipedia article:

Autovivification is a distinguishing feature of the Perl programming language involving the dynamic creation of data structures. Autovivification is the automatic creation of a variable reference when an undefined value is dereferenced. In other words, Perl autovivification allows a programmer to refer to a structured variable, and arbitrary sub-elements of that structured variable, without expressly declaring the existence of the variable and its complete structure beforehand.

For example:

#! /usr/bin/perl

use warnings;

my %foo;
++$foo{bar}{baz}{quux};

use Data::Dumper;
$Data::Dumper::Indent = 1;
print Dumper \%foo;

Even though we don t explicitly initialize the intermediate keys, Perl takes care of the scaffolding:

$VAR1 = {
   bar  => {
     baz  => {
       quux  =>  1 
    }
  }
};

Without autovivification, the code would require more boilerplate:

my %foo;
$foo{bar} = {};
$foo{bar}{baz} = {};
++$foo{bar}{baz}{quux};  # finally!

Don t confuse autovivification with the undefined values it can produce. For example with

#! /usr/bin/perl

use warnings;

my %foo;
print $foo{bar}{baz}{quux}, "
";
use Data::Dumper;
$Data::Dumper::Indent = 1;
print Dumper \%foo;

we get

Use of uninitialized value in print at ./prog.pl line 6.

$VAR1 = {
   bar  => {
     baz  => {}
  }
};

Notice that the intermediate keys autovivified.

Other examples of autovivification:

  • reference to array

    my $a;
    push @$a => "foo";
    
  • reference to scalar

    my $s;
    ++$$s;
    
  • reference to hash

    my $h;
    $h->{foo} = "bar";
    

Sadly, Perl does not (yet!) autovivify the following:

my $code;
$code->("Do what I need please!");

Other mutators

In an answer to a similar question, ysth reports

Certain operators deliberately omit the "uninitialized" warning for your convenience because they are commonly used in situations where a 0 or "" default value for the left or only operand makes sense.

These are: ++ and -- (either pre- or post-), +=, -=, .=, |=, ^=, &&=, ||=.

Being "defined-or," //= happily mutates an undefined value without warning.

问题回答

So far the cases I ve found are:

  • autovivification (gbacon s answer)
  • boolean context, like if $foo or $foo || $bar
  • with ++ or --
  • left side of +=, -=, or .=

Are there others?

Always fix warnings even the pesky annoying ones.

Undefined warnings can to be turned off. You can do that by creating a new scope for the operation. See perldoc perllexwarn for more info. This method works across all versions of perl.

{
  no warnings  uninitialized ;
  my $foo = "foo" + undef = "bar";
}

For a lot of the binary operators, you can use the new Perl 5.10 stuff, ~~ and //; See perldoc perlop for more info.

use warnings;
my $foo = undef;
my $bar = $foo //   ; ## same as $bar = defined $foo ? $foo :   

also is the //= variant which sets the variable if it is undefined:

$foo //=   ;

The Smart Matching (~~) operator is kind of cool, and permits smart comparisons, this is kind of nifty check it out in perldoc perlsyn:

use warnings;
my $foo = "string";
say $foo eq undef;  # triggers warnings
say $foo ~~ undef;  # no undef warnings

The real answer should be: why would you want to turn on that warning? undef is a perfectly good value for a variable (as anyone who s ever worked with a database can tell you), and it often makes sense to differentiate between true (something happened), false (nothing happened) and undef (an error occurred).

Rather than saying

use strict;
use warnings;

say

use common::sense;

and you ll get all the benefits of warnings, but with the annoying ones like undefined variables turned off.

common::sense is available from the CPAN.





相关问题
Why does my chdir to a filehandle not work in Perl?

When I try a "chdir" with a filehandle as argument, "chdir" returns 0 and a pwd returns still the same directory. Should that be so? I tried this, because in the documentation to chdir I found: "...

How do I use GetOptions to get the default argument?

I ve read the doc for GetOptions but I can t seem to find what I need... (maybe I am blind) What I want to do is to parse command line like this myperlscript.pl -mode [sth] [inputfile] I can use ...

Object-Oriented Perl constructor syntax and named parameters

I m a little confused about what is going on in Perl constructors. I found these two examples perldoc perlbot. package Foo; #In Perl, the constructor is just a subroutine called new. sub new { #I ...

Where can I find object-oriented Perl tutorials? [closed]

A Google search yields a number of results - but which ones are the best? The Perl site appears to contain two - perlboot and perltoot. I m reading these now, but what else is out there? Note: I ve ...

热门标签