Perl:哈希切片不能在词法范围内
Perl: Hash slices cannot be lexically scoped
我真的不知道,为什么这是错误的:
#!/usr/bin/perl
use v5.20;
package MyDate;
sub new{ bless {}, shift; }
sub AUTOLOAD{
my $f = our $AUTOLOAD;
my @h{qw[Wday Month Year]} = (localtime)[3,4,5];
}
Err:"@h{"
附近的编译错误
如果我删除 my
(或者即使包范围为 our
):
@h{qw[Wday Month Year]} = (localtime)[3,4,5];
它会神奇地起作用。为什么散列切片不能是词法范围的?
编辑:是的 - 我没有注意到,(localtime)[3] = mday
不是 wday。但这不是重点。我问的是作用域,不是本地时间函数。
Edit2:散列 %h
(我的问题的重点),旨在用于 autoload
子内部(当然,当我尝试将其用作散列切片时那里)。只是为了清楚起见。
我希望你能从下面的代码中看到你的错误
use strict;
use warnings;
use diagnostics;
use v5.20;
package MyDate;
sub new{ bless {}, shift; }
sub AUTOLOAD{
my $f = our $AUTOLOAD;
#my %h; # !!! without hash declaration compilation error
# 0 1 2 3 4 5 6 7 8
#my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
# localtime(time);
@h{qw[Wday Month Year]} = (localtime)[6,4,5];
}
perl hash_package.pl
Global symbol "%h" requires explicit package name (did you forget to declare "my %h"?) at hash_package.pl line 15.
Execution of hash_package.pl aborted due to compilation errors (#1)
(F) You've said "use strict" or "use strict vars", which indicates
that all variables must either be lexically scoped (using "my" or "state"),
declared beforehand using "our", or explicitly qualified to say
which package the global variable is in (using "::").
Uncaught exception from user code:
Global symbol "%h" requires explicit package name (did you forget to declare "my %h"?) at hash_package.pl line 15.
Execution of hash_package.pl aborted due to compilation errors.
@h{...}
不是一个变量,所以你不能这样声明它。
@h{...} = ...;
设置 %h
的元素。因此,您需要创建 %h
。
具体操作如下:
my %h;
顺便说一下,我怀疑您是否有正当理由使用 AUTOLOAD
。请记住,模块的顶层(文件级)代码将在模块首次加载到解释器中时执行。
这只是 OP 试图做的事情的一个大摇摆。因此,根据站点惯例,这是一个非常糟糕的 SO 答案,但我认为这可能有助于为我们痛苦的 OP 澄清水域。
我将从 OP 发布的代码开始,对其进行一些评论,然后转到 "right way to do it" 的几个示例。
OP 代码:
#!/usr/bin/perl
所以我们是 运行 脚本。
use v5.20;
使用 5.20 或更高版本。到目前为止,还不错。
package MyDate;
现在我们选择了一个名为 MyDate
的新 namespace/package。虽然这不是违法的,但通常认为每个文件一个包是可取的。
sub new{ bless {}, shift; }
我们有一个构造函数。所以 MyDate
将成为 class。或许值得看看 Moose 或 Moo 以帮助自动化一些使用 class 构造的无聊废话。但是使用良好的 ole' classical Perl 对象没有任何问题。
sub AUTOLOAD{
my $f = our $AUTOLOAD;
my @h{qw[Wday Month Year]} = (localtime)[3,4,5];
}
语法错误,一切痛苦的根源。 AUTOLOAD
被调用以处理命名空间中的任何未知函数调用。因此,这实际上拦截了所有未定义的方法调用。 MyDate 有无限的方法列表。这可能不是真正需要的。
让我们稍微修改一下:
这是我对 OP 在他们的脚本文件中可能需要的东西的猜测:
#!/usr/bin/perl
use v5.20;
use strict; # Make life easier by catching bugs at compile time.
use warnings; # Catch things that probably indicate errors, but aren't technically illegal.
use MyDate; # Load my date class
# Make some dates
my $today = MyDate->new();
my $aprilish = MyDate->new( month => 4 );
# Do stuff with them!
print_date( $today );
print_date( $aprilish );
sub print_date {
my ($date) = @_;
say "Weekday: ", $date->wday();
say "Month: ", $date->month();
say "Year: ", $date->year();
}
库文件:MyDate.pm
package MyDate;
use v5.20; # Set the minimum perl version required. Optional, but useful.
use strict; # Always
use warnings;
sub new {
my ($class, %parts) = @_;
my %defaults; @defaults[wday month year] = localtime(3, 4, 5)
my $self = bless {
%defaults,
}, $class;
for my $part ( qw/ month wday year /) {
next unless exists $parts{$part};
$self->$part( $parts{$part} ); # Call the associated method to initialize an attribute.
delete $parts{$part};
}
die "Unknown attributes: ", join ', ', keys %parts # Fatal error on unknown args
if %parts;
return $self;
}
# The other methods are mostly identical.
sub month {
my ($self, $value) = @_;
if ( @_ == 2 ) { # If two args are passed, we are a setter.
$self->{month} = $value;
}
return $self->{month};
}
我认为这是类似于 OP 的 classical perl OO 版本。
用Moo.
写起来省事多了
package MyDate;
use v5.20; # Set the minimum perl version required. Optional, but useful.
use Moo; # Turns on strict and warnings;
use namespace::autoclean; # Removes any utility functions so they don't show up as methods.
has 'month' => (
is => 'ro',
builder => 1,
);
has 'wday' => (
is => 'ro',
builder => 1,
);
has 'year' => (
is => 'ro',
builder => 1,
);
sub _build_month { localtime()[4] }
sub _build_wday { localtime()[3] }
sub _build_year { localtime()[5] }
但最好的办法可能是采用现有的日期操作库,如 DateTime 并使用它。
#!/usr/bin/perl
use v5.20;
use strict; # Make life easier by catching bugs at compile time.
use warnings; # Catch things that probably indicate errors, but aren't technically illegal.
use DateTime; # Load my date class
# Make some dates
my $today = DateTime->today();
my $aprilish = DateTime->today()->set_month( 4 );
# Do stuff with them!
print_date( $today );
print_date( $aprilish );
sub print_date {
my ($date) = @_;
say "Weekday: ", $date->day_of_week();
say "Month: ", $date->month();
say "Year: ", $date->year();
}
无论如何,我希望所有这些对 OP 有用,也许对其他人有用。
我真的不知道,为什么这是错误的:
#!/usr/bin/perl
use v5.20;
package MyDate;
sub new{ bless {}, shift; }
sub AUTOLOAD{
my $f = our $AUTOLOAD;
my @h{qw[Wday Month Year]} = (localtime)[3,4,5];
}
Err:"@h{"
如果我删除 my
(或者即使包范围为 our
):
@h{qw[Wday Month Year]} = (localtime)[3,4,5];
它会神奇地起作用。为什么散列切片不能是词法范围的?
编辑:是的 - 我没有注意到,(localtime)[3] = mday
不是 wday。但这不是重点。我问的是作用域,不是本地时间函数。
Edit2:散列 %h
(我的问题的重点),旨在用于 autoload
子内部(当然,当我尝试将其用作散列切片时那里)。只是为了清楚起见。
我希望你能从下面的代码中看到你的错误
use strict;
use warnings;
use diagnostics;
use v5.20;
package MyDate;
sub new{ bless {}, shift; }
sub AUTOLOAD{
my $f = our $AUTOLOAD;
#my %h; # !!! without hash declaration compilation error
# 0 1 2 3 4 5 6 7 8
#my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
# localtime(time);
@h{qw[Wday Month Year]} = (localtime)[6,4,5];
}
perl hash_package.pl
Global symbol "%h" requires explicit package name (did you forget to declare "my %h"?) at hash_package.pl line 15.
Execution of hash_package.pl aborted due to compilation errors (#1)
(F) You've said "use strict" or "use strict vars", which indicates
that all variables must either be lexically scoped (using "my" or "state"),
declared beforehand using "our", or explicitly qualified to say
which package the global variable is in (using "::").
Uncaught exception from user code:
Global symbol "%h" requires explicit package name (did you forget to declare "my %h"?) at hash_package.pl line 15.
Execution of hash_package.pl aborted due to compilation errors.
@h{...}
不是一个变量,所以你不能这样声明它。
@h{...} = ...;
设置 %h
的元素。因此,您需要创建 %h
。
具体操作如下:
my %h;
顺便说一下,我怀疑您是否有正当理由使用 AUTOLOAD
。请记住,模块的顶层(文件级)代码将在模块首次加载到解释器中时执行。
这只是 OP 试图做的事情的一个大摇摆。因此,根据站点惯例,这是一个非常糟糕的 SO 答案,但我认为这可能有助于为我们痛苦的 OP 澄清水域。
我将从 OP 发布的代码开始,对其进行一些评论,然后转到 "right way to do it" 的几个示例。
OP 代码:
#!/usr/bin/perl
所以我们是 运行 脚本。
use v5.20;
使用 5.20 或更高版本。到目前为止,还不错。
package MyDate;
现在我们选择了一个名为 MyDate
的新 namespace/package。虽然这不是违法的,但通常认为每个文件一个包是可取的。
sub new{ bless {}, shift; }
我们有一个构造函数。所以 MyDate
将成为 class。或许值得看看 Moose 或 Moo 以帮助自动化一些使用 class 构造的无聊废话。但是使用良好的 ole' classical Perl 对象没有任何问题。
sub AUTOLOAD{
my $f = our $AUTOLOAD;
my @h{qw[Wday Month Year]} = (localtime)[3,4,5];
}
语法错误,一切痛苦的根源。 AUTOLOAD
被调用以处理命名空间中的任何未知函数调用。因此,这实际上拦截了所有未定义的方法调用。 MyDate 有无限的方法列表。这可能不是真正需要的。
让我们稍微修改一下:
这是我对 OP 在他们的脚本文件中可能需要的东西的猜测:
#!/usr/bin/perl
use v5.20;
use strict; # Make life easier by catching bugs at compile time.
use warnings; # Catch things that probably indicate errors, but aren't technically illegal.
use MyDate; # Load my date class
# Make some dates
my $today = MyDate->new();
my $aprilish = MyDate->new( month => 4 );
# Do stuff with them!
print_date( $today );
print_date( $aprilish );
sub print_date {
my ($date) = @_;
say "Weekday: ", $date->wday();
say "Month: ", $date->month();
say "Year: ", $date->year();
}
库文件:MyDate.pm
package MyDate;
use v5.20; # Set the minimum perl version required. Optional, but useful.
use strict; # Always
use warnings;
sub new {
my ($class, %parts) = @_;
my %defaults; @defaults[wday month year] = localtime(3, 4, 5)
my $self = bless {
%defaults,
}, $class;
for my $part ( qw/ month wday year /) {
next unless exists $parts{$part};
$self->$part( $parts{$part} ); # Call the associated method to initialize an attribute.
delete $parts{$part};
}
die "Unknown attributes: ", join ', ', keys %parts # Fatal error on unknown args
if %parts;
return $self;
}
# The other methods are mostly identical.
sub month {
my ($self, $value) = @_;
if ( @_ == 2 ) { # If two args are passed, we are a setter.
$self->{month} = $value;
}
return $self->{month};
}
我认为这是类似于 OP 的 classical perl OO 版本。
用Moo.
写起来省事多了package MyDate;
use v5.20; # Set the minimum perl version required. Optional, but useful.
use Moo; # Turns on strict and warnings;
use namespace::autoclean; # Removes any utility functions so they don't show up as methods.
has 'month' => (
is => 'ro',
builder => 1,
);
has 'wday' => (
is => 'ro',
builder => 1,
);
has 'year' => (
is => 'ro',
builder => 1,
);
sub _build_month { localtime()[4] }
sub _build_wday { localtime()[3] }
sub _build_year { localtime()[5] }
但最好的办法可能是采用现有的日期操作库,如 DateTime 并使用它。
#!/usr/bin/perl
use v5.20;
use strict; # Make life easier by catching bugs at compile time.
use warnings; # Catch things that probably indicate errors, but aren't technically illegal.
use DateTime; # Load my date class
# Make some dates
my $today = DateTime->today();
my $aprilish = DateTime->today()->set_month( 4 );
# Do stuff with them!
print_date( $today );
print_date( $aprilish );
sub print_date {
my ($date) = @_;
say "Weekday: ", $date->day_of_week();
say "Month: ", $date->month();
say "Year: ", $date->year();
}
无论如何,我希望所有这些对 OP 有用,也许对其他人有用。