【问题标题】:Locally change an attribute of a class in Perl在 Perl 中本地更改类的属性
【发布时间】:2015-11-29 19:38:13
【问题描述】:

我在我的一个 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();

有没有办法实现这样的目标?

【问题讨论】:

  • 一个简单但不起眼的技巧是将原始值存储在范围顶部的新变量中,做你的事情,然后在底部恢复原始值。
  • 如果你可以在块内或块外调用不同的方法(具有不同的实现),这将起作用。

标签: perl oop scope lexical-scope


【解决方案1】:

这可能不像您要求的那样封装,但您可以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-ize 整个方法。这也会输出"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;

【讨论】:

    【解决方案2】:

    我完全误解了那里发生的事情。您不能在子例程调用中使用 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、OR 文件创建范围(你的问题在那里)

    如果您能够在没有方法调用的情况下直接访问元素(恕我直言,这是不好的做法),您可能能够在对象中本地化该元素的范围。

    例子:

    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、eval 和许多 perl 关键字这样的东西会根据上下文做不同的事情。它没有点击该问题是在方法调用上调用本地问题
    • 但是,您完全可以自己回答问题,而不是仅仅为了责备而发帖;)
    猜你喜欢
    • 1970-01-01
    • 2017-06-06
    • 1970-01-01
    • 2015-12-08
    • 2013-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多