如何解决是否可以在不定义getter的情况下访问ATTR for Perl软件包?
我目前正在从事Perl 5.8项目。 我的包裹看起来像:
package Foo::Bar;
use strict;
use warnings;
use Class::Std;
our @EXPORT_SAFE = qw(Class::Std);
my %baz :ATTR;
sub BUILD {
my ($self,$ident,$args) = @_;
$baz{$ident} = $$args{something};
}
我不会用任何吸气剂来暴露baz
,但是我想获取它的内容用于单元测试。在Perl中有什么方法可以做到?
例如在Ruby中,您可以some_instance.instance_variable_get("@#{name}")
非常感谢您
解决方法
TL; DR
通常情况下的答案是“取决于(但可能)”。
在您的情况下,答案是“否”。
详细信息
在Perl中没有固定的方法来实现类和对象。在大多数情况下,对象将是对哈希的有福的引用。在这些情况下,您可以简单地将对象引用视为哈希引用,然后直接查找键。因此,这样的代码:
my $baz = $obj->{baz};
但是,您没有使用最常见的构建Perl对象的方法,而是使用了Class::Std。与Class :: Std所做的事情大不相同。 Class :: Std使用一种称为“由内而外的对象”的方法,该方法由Damian Conway在 Object Oriented Perl 中流行,并且在大约20年前非常流行。
在普通对象中,每个对象都有一个哈希。键是属性名称,值是属性值。对于由内而外的对象,每个属性都有其自己的哈希。键是对单个对象的字符串化引用,其值是该对象的属性值。
实际上,“标准”方法是:
$object{attr} = value;
由内而外的方法是:
$attr{object} = value;
人们喜欢由内而外的对象的主要原因之一是,属性哈希可以是存储在类源代码中的词法变量。这意味着它们是真正的私有对象,除非使用所提供的访问器方法,否则不能从类外部访问它们。如果您想强制Perl实现更强大的封装,那将是很好的选择。但是,如果您想以此处的方式突破这种封装,那就太糟糕了。
所以,不。就您而言,您不能这样做。
, Class :: Std可以轻松提供->instance_variable_get
,至少对于已命名的变量。 [1] 但事实并非如此。
如果没有Class :: Std提供的某些内容,则可以将以下内容添加到您的课程中:
use Carp qw( croak );
sub instance_variable_get {
my ($self,$name) = @_;
my $pkg_glob = do {
no strict qw( refs );
*{ __PACKAGE__ . "::" }
};
exists($pkg_glob->{$name})
or croak("Unknown attribute $name");
my $hash = *{ $pkg_glob->{$name} }{HASH}
or croak("Unknown attribute $name");
return $hash->{ident($self)};
}
请注意,这需要使用our
而不是my
进行哈希处理。
这将允许您使用
$some_instance->instance_variable_get('baz')
当然,如果您使用our
作为哈希值,则也可以使用
$Foo::Bar::baz{ $some_instance->ident }
- 当前,
:ATTR( :name<...> )
,:ATTR( :init_arg<...> )
,:ATTR( :get<...> )
和:ATTR( :set<...> )
为属性提供了名称,尽管它们也具有其他作用。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。