我是perl的新手.我试图通过编写一些程序来理解它.在perl中确定范围让我很难过.
我写了以下内容:
use 5.16.3;
use strict;
use Getopt::Long;
Getopt::Long::Configure(qw(bundling no_getopt_compat));
&ArgParser;
our ($sqluser,$sqlpass);
$sqluser="root";
$sqlpass="mypassword";
sub ArgParser {
print "Username is ".$sqluser." Password is ".$sqlpass."\n";
my $crt='';
my $delete='';
GetOptions ('create|c=s' => \$crt,
'delete|d=s' => \$delete
);
if ($crt) {
&DatabaseExec("create",$crt);
} elsif ($delete) {
&DatabaseExec("delete",$delete);
} else {
print "No options chosen\n";
}
}
sub DatabaseExec {
use DBI;
my $dbname=$_[1];
print "Username is ".$sqluser." Password is ".$sqlpass."\n";
my $dbh = DBI->connect("dbi:mysql:", $sqluser,$sqlpass);
my $comand=$_[0];
if ($_[0] eq "create") {
my $db_com="create database ".$dbname;
print 1 == $dbh->do($db_com) ? "Database created\n":"An error occured while creating database. Maybe it exists?\n";
#print "Executing: ".$db_com."\n";
} elsif ($_[0] eq "delete") {
my $db_com="DROP DATABASE ".$dbname;
#print "Executing: ".$db_com."\n";
print 1 == $dbh->do($db_com) ? "Database deleted\n":"An error occured while creating database. Maybe it exists?\n";
}
}
Run Code Online (Sandbox Code Playgroud)
我的理解是,我们会将这些声明为主代码和子程序的全局变量.但是,这给出了以下输出:
#~/perlscripts/dbtest.pl -c hellos
Use of uninitialized value $sqluser in concatenation (.) or string at /root/perlscripts/dbtest.pl line 20.
Use of uninitialized value $sqlpass in concatenation (.) or string at /root/perlscripts/dbtest.pl line 20.
Username is Password is
Use of uninitialized value $sqluser in concatenation (.) or string at /root/perlscripts/dbtest.pl line 44.
Use of uninitialized value $sqlpass in concatenation (.) or string at /root/perlscripts/dbtest.pl line 44.
Username is Password is
DBI connect('','',...) failed: Access denied for user 'root'@'localhost' (using password: NO) at /root/perlscripts/dbtest.pl line 45.
Can't call method "do" on an undefined value at /root/perlscripts/dbtest.pl line 50.
Run Code Online (Sandbox Code Playgroud)
我不想将这些作为参数传递给sub,而宁愿将它们用作全局变量.有人可以帮我确定我对范围界定的误解吗?
TLP*_*TLP 11
调用子例程时,不会声明变量:
&ArgParser; # subroutine call
our ($sqluser,$sqlpass); # declaration
$sqluser="root"; # assignment
$sqlpass="mypassword";
Run Code Online (Sandbox Code Playgroud)
为了在子例程中使用这些全局变量,将子例程放在变量声明之后.
但是,使用全局变量是一件坏事,您应该尽可能避免使用它.你可以这样做,例如:
my $sqluser = "root";
my $sqlpass = "mypass";
ArgParser($sqluser, $sqlpass); # you should not use & in subroutine calls
Run Code Online (Sandbox Code Playgroud)
然后在子程序内:
sub ArgParser {
my ($sqluser, $sqlpass) = @_;
...
Run Code Online (Sandbox Code Playgroud)
这样,您的变量就可以很好地封装,并且不会被意外操作.
关于&子程序调用中的&符号,这在perldoc perlsub中有记录:
To call subroutines:
NAME(LIST); # & is optional with parentheses.
NAME LIST; # Parentheses optional if predeclared/imported.
&NAME(LIST); # Circumvent prototypes.
&NAME; # Makes current @_ visible to called subroutine.
Run Code Online (Sandbox Code Playgroud)
Perl没有全局变量.Perl的含义是:
包是命名空间.在Perl中,命名空间有时称为包.您的默认包名称是main.例如.这是完全合法的:
use strict;
use warnings;
$main::variable = "What? Where's my 'our' or 'my' declaration?";
print "Look, I can print $main::variable without using 'my' or 'our'!";
Run Code Online (Sandbox Code Playgroud)
我只是用包装前缀我的包变量名称,并且!他们存在!
这让我惊愕:
use strict;
use warnings;
$variable = "What? Where's my 'our' or 'my' declaration?";
print "I'm not going to print 'cause you're going to get a compilation error";
Run Code Online (Sandbox Code Playgroud)
使用use strict;,您必须将变量声明为our或my,或者在其前面加上它所在的包的名称.
包变量最容易理解.包变量实际上存储在Perl变量结构中,因此它们在声明后始终可用:
use strict;
use warnings;
if ( 1 == 1 ) { #Yes, I know this is always true
our $foo = "I have a value!";
}
say "Looks like $foo has a value";
Run Code Online (Sandbox Code Playgroud)
词汇范围的变量更难理解.基本上,词法范围变量在其定义的块中的范围内,但是一旦离开该块,就超出范围.它也可以在子块中使用:
use strict;
use warnings;
my $foo = "Foo has a value";
if ( $foo ) { #Always true
my $bar = "bar has a value";
print "$foo\n"; # $foo has a value. This is a sub-block
print "$bar\n"; # $bar has a value. It was defined in this block
}
print "$foo\n"; # $foo still has a value.
print "$bar\n"; # You'll get en error here. $bar out of scope here
Run Code Online (Sandbox Code Playgroud)
以下是一些建议:
my变量,它们将在子程序中可用,因为它们仍然在范围内.&子程序调用.它们会导致子程序工作方式发生细微变化,这些微妙的变化可能不是你想要的.标准只是调用子程序.
? ... : ...,特别是如果你没有使用空格.它使您的程序更难阅读,并且不会节省任何执行时间.my变量将起作用,但常量可以确保您的程序中不会意外更改这些值.这是你的代码重写.请注意,常量前面没有印记.这些通常不能用字符串插值.但是,如果用它们包围它们@{[...]},也可以插入它们.我在下面做了两件事:
use 5.16.3;
use strict;
use Getopt::Long;
use constant {
SQL_USER => "root",
SQL_PASS => "mypassword",
};
Getopt::Long::Configure qw(bundling no_getopt_compat);
sub ArgParser {
print "Username is " SQL_USER . " Password is " . SQL_PASS . "\n";
my $crt;
my $delete;
GetOptions (
'create|c=s' => \$crt,
'delete|d=s' => \$delete,
);
if ( $crt ) {
DatabaseExec( "create", $crt );
}
elsif ( $delete ) {
DatabaseExec( "delete", $delete );
}
else {
print "No options chosen\n";
}
}
sub DatabaseExec {
use DBI;
my $comand = shift;
my $dbname = shift;
print "Username is @{[SQL_USER]} Password is @{[SQL_PASS]}\n";
my $dbh = DBI->connect(
"dbi:mysql:",
SQL_USER,
SQL_PASS
);
if ( $command eq "create" ) {
my $db_com = "create database $dbname";
if ( $dbh->do( $db_com ) ) {
print "Database created\n"
}
else {
print "An error occured while creating database. Maybe it exists?\n";
}
} elsif ( $command eq "delete" ) {
my $db_com = "DROP DATABASE $dbname";
#print "Executing: ".$db_com."\n";
if ( $dbh->do($db_com) ) {
print "Database deleted\n";
}
else {
print "An error occured while creating database. Maybe it exists?\n";
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
12809 次 |
| 最近记录: |