在 Perl 中本地更改 class 的属性
Locally change an attribute of a class in Perl
我在我的一个 Perl 脚本中遇到了一个奇怪的问题。我有一个 Perl 对象。在某个范围内,我希望更改其中一个对象属性,但我希望该属性在离开范围后恢复到它的旧值。
示例:
my $object = Object->new('name' => 'Bob');
{
# I know this doesn't work, but it is the best way
# I can represent what I amd trying to do.
local $object->name('Lenny');
# Prints "Lenny"
print $object->name();
}
# Prints "Bob"
print $object->name();
有没有办法实现这样的目标?
我完全误解了那里发生的事情。您不能在子例程调用中使用 local,这是您遇到的问题。
让我们使用一个我知道可行的代码示例,并尝试解释 eval 的实际作用。
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use Cwd;
print getcwd() . "\n";
eval{
local @INC = ('/tmp');
require 'test.pl';
print 'local: ' . Dumper(\@INC);
};
print Dumper(\@INC);
这是可行的,因为我正在修改一个变量,而不是调用另一个子例程来修改我的变量。
为了使其按您的预期工作,您必须创建对象的深层副本以在本地范围或类似的范围内进行修改。 (我很确定首先发生的是什么)
local 为给定的括号、eval 或文件创建范围(你的问题在那里)
如果您能够在不调用方法的情况下直接访问元素(不好的做法恕我直言),您可能能够在对象中本地化该元素的范围。
示例:
name.pm:
package name;
use strict;
use warnings;
{
sub new {
my ($class,$name) = @_;
my $self = bless {}, $class;
$self->{'name'} = $name if defined $name;
return $self;
}
sub name
{
my ($self,$name) = @_;
$self->{'name'} = $name if defined $name;
return $self->{'name'};
}
}
index.pl:
#!/usr/bin/perl -w
use strict;
use warnings FATAL => 'all';
use name;
my $obj = name->new('test');
print $obj->{'name'} . "\n";
{
local $obj->{'name'} = 'test2';
print $obj->{'name'} . "\n";
}
print $obj->{'name'} . "\n";
这可能没有您要求的那么多封装,但您可以 local
-ize 散列的属性。这输出 "CarlLennyCarl"
sub Object::new { bless { _name => $_[1] }, $_[0] } }
sub Object::name { $_[0]->{_name} }
my $obj = Object->new("Carl");
print $obj->name;
{
local $obj->{_name} = "Lenny";
print $obj->name;
}
print $obj->name;
您也可以 local
化整个方法。这也输出 "CarlLennyCarl"
:
sub Object::new { bless { _name => $_[1] }, $_[0] } }
sub Object::name { $_[0]->{_name} }
my $obj = Object->new("Carl");
print $obj->name;
{
local *Object::name = sub { "Lenny" };
print $obj->name;
}
print $obj->name;
我在我的一个 Perl 脚本中遇到了一个奇怪的问题。我有一个 Perl 对象。在某个范围内,我希望更改其中一个对象属性,但我希望该属性在离开范围后恢复到它的旧值。
示例:
my $object = Object->new('name' => 'Bob');
{
# I know this doesn't work, but it is the best way
# I can represent what I amd trying to do.
local $object->name('Lenny');
# Prints "Lenny"
print $object->name();
}
# Prints "Bob"
print $object->name();
有没有办法实现这样的目标?
我完全误解了那里发生的事情。您不能在子例程调用中使用 local,这是您遇到的问题。
让我们使用一个我知道可行的代码示例,并尝试解释 eval 的实际作用。
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use Cwd;
print getcwd() . "\n";
eval{
local @INC = ('/tmp');
require 'test.pl';
print 'local: ' . Dumper(\@INC);
};
print Dumper(\@INC);
这是可行的,因为我正在修改一个变量,而不是调用另一个子例程来修改我的变量。
为了使其按您的预期工作,您必须创建对象的深层副本以在本地范围或类似的范围内进行修改。 (我很确定首先发生的是什么)
local 为给定的括号、eval 或文件创建范围(你的问题在那里)
如果您能够在不调用方法的情况下直接访问元素(不好的做法恕我直言),您可能能够在对象中本地化该元素的范围。
示例:
name.pm:
package name;
use strict;
use warnings;
{
sub new {
my ($class,$name) = @_;
my $self = bless {}, $class;
$self->{'name'} = $name if defined $name;
return $self;
}
sub name
{
my ($self,$name) = @_;
$self->{'name'} = $name if defined $name;
return $self->{'name'};
}
}
index.pl:
#!/usr/bin/perl -w
use strict;
use warnings FATAL => 'all';
use name;
my $obj = name->new('test');
print $obj->{'name'} . "\n";
{
local $obj->{'name'} = 'test2';
print $obj->{'name'} . "\n";
}
print $obj->{'name'} . "\n";
这可能没有您要求的那么多封装,但您可以 local
-ize 散列的属性。这输出 "CarlLennyCarl"
sub Object::new { bless { _name => $_[1] }, $_[0] } }
sub Object::name { $_[0]->{_name} }
my $obj = Object->new("Carl");
print $obj->name;
{
local $obj->{_name} = "Lenny";
print $obj->name;
}
print $obj->name;
您也可以 local
化整个方法。这也输出 "CarlLennyCarl"
:
sub Object::new { bless { _name => $_[1] }, $_[0] } }
sub Object::name { $_[0]->{_name} }
my $obj = Object->new("Carl");
print $obj->name;
{
local *Object::name = sub { "Lenny" };
print $obj->name;
}
print $obj->name;