返回延迟计算的标量(以perl为单位)
我试图通过使用绑定标量向我们的代码库添加一些功能 我们有一个指定返回标量的函数。我想我可以通过在返回标量之前绑定这些标量来向系统添加一些特性,但是看起来FETCH方法在返回之前被调用,这导致返回一个未绑定的标量 这有什么办法吗 如果可能的话,我真的希望保持子例程的接口(返回标量)完好无损返回延迟计算的标量(以perl为单位),perl,fetch,scalar,tie,Perl,Fetch,Scalar,Tie,我试图通过使用绑定标量向我们的代码库添加一些功能 我们有一个指定返回标量的函数。我想我可以通过在返回标量之前绑定这些标量来向系统添加一些特性,但是看起来FETCH方法在返回之前被调用,这导致返回一个未绑定的标量 这有什么办法吗 如果可能的话,我真的希望保持子例程的接口(返回标量)完好无损 use strict; use warnings; main(); sub GetThing{ my $thing; tie $thing, 'mything', @_; return
use strict;
use warnings;
main();
sub GetThing{
my $thing;
tie $thing, 'mything', @_;
return $thing;
}
sub main {
my %m;
$m{pre} = GetThing('Fred');
print "1\n";
print $m{pre};
print "2\n";
print $m{pre};
print "3\n";
}
package mything;
require Tie::Scalar;
my @ISA = qw(Tie::StdScalar);
sub TIESCALAR {
my $class = shift;
bless {
name => shift || 'noname',
}, $class;
}
sub FETCH {
my $self = shift;
print "ACCESS ALERT!\n";
return " NAME: '$self->{name}'\n";
}
期望输出:
1
ACCESS ALERT!
NAME: 'Fred'
2
ACCESS ALERT!
NAME: 'Fred'
3
我可以通过返回一个引用并在每次访问时取消引用来获得所需的输出,但这会破坏我们已建立的界面,并使我们的用户更加困惑
--Buck首先,做你提议的事情的确切方法在技术上似乎是不可能的:
return
的值,访问它(在您的情况下,访问绑定变量并在过程中调用FETCH
),然后复制该值!这意味着调用者得到的是标量值,而不是标量变量(绑定或未绑定)第二,您不太清楚自己到底想实现什么,因此很难提出如何实现自己的目标。但是,根据您的描述,假设您希望在子例程返回时调用某个方法(可能将返回值传递给它),您可以这样做 要做到这一点,你需要使用那些花哨的人所说的。在Perl中,政治上(技术上)正确的方法是使用Moose 但是,您可以通过基本上用包装器方法替换原始方法来DIY它 驼鹿和DIY方法的确切机制可以在以下SO问题的前两个答案中看到,因此我不会将它们复制/粘贴到这里,希望您不介意:
正如DVK所说,tie适用于容器,因此对于返回值没有用处 为此,可以使用重载。示例(未提供所有可能的重载操作;请参阅):
如其他答案所述,
tie
适用于容器,而不适用于值,因此无法将绑定变量分配给另一个变量并保留绑定属性
由于分配已结束,您需要将容器传递到GetThing
例程中。您可以按如下方式通过引用执行此操作:
use strict;
use warnings;
main();
sub GetThing{
tie ${$_[1]}, 'mything', $_[0];
}
sub main {
my %m;
GetThing('Fred' => \$m{pre});
print "1\n";
print $m{pre};
print "2\n";
print $m{pre};
print "3\n";
}
package mything;
require Tie::Scalar;
my @ISA = qw(Tie::StdScalar);
sub TIESCALAR {
my $class = shift;
bless {
name => shift || 'noname',
}, $class;
}
sub FETCH {
my $self = shift;
print "ACCESS ALERT!\n";
return " NAME: '$self->{name}'\n";
}
这将产生正确的输出
但是,如果要保留赋值,则需要使用重载,这适用于值(实际上是对象,但它们本身就是值)。如果没有更多关于您预期目的的详细信息,很难给出完整的答案,但这将满足您所述的要求:
use strict;
use warnings;
main();
sub GetThing{
return mything->new( shift );
}
sub main {
my %m;
$m{pre} = GetThing('Fred');
print "1\n";
print $m{pre};
print "2\n";
print $m{pre};
print "3\n";
}
package mything;
sub new {
my $class = shift;
bless {
name => shift || 'noname',
}, $class;
}
use overload '""' => sub { # '""' means to overload stringification
my $self = shift;
print "ACCESS ALERT!\n";
return " NAME: '$self->{name}'\n";
};
绑定和重载都可能变得复杂,因此如果有什么不清楚的地方,请通读所有文档。如果您觉得有冒险精神,您也可以使用模块,该模块为标量变量提供了一种通用机制,可以在每次访问时惰性地计算值。警告:我从未使用绑定标量,因此,答案的第一部分仅仅是我分析文档的结果,因此可能与基于理论的任何东西都有很大差距。。。如果有人提供了更好的线索,我会很高兴地删除它。当返回的子例程声明为
左值时,变量和值之间的界限就会变得模糊(因为FETCH
和STORE
在这种情况下都起作用)。您还可以引用返回的别名,该别名在取消引用时保留绑定操作。@Eric Strom:如果您遇到这种麻烦,不妨让例程在第一次返回引用(或传递引用!)place@ysth=>我不太明白你的意思。您的意思是返回对绑定标量的引用吗?这将迫使用户每次都取消对它的引用,这似乎破坏了绑定界面的优雅。我的观点更多的是,你“可以”引用,证明返回的“值”是绑定变量。请看一下我的模块Lvalue
()的源代码,以了解绑定标量和Lvalue子例程如何结合在一起扩展perl的语法(没有传统的Lvalue子例程固有的封装冲突)@DVK:谢谢,我阅读了您的链接帖子,但无法弄清楚它在这里是如何应用的。。。你能说得更清楚些吗?我真的很想找到一个perl内置解决方案(我想是DIY),而不是安装一个新的模块。可根据要求提供代码。
-request。您能否详细说明在这种情况下如何应用重载?谢谢!是的,请详细说明。我认为tie()是在标量上重载获取的正确方法。@buzkor:在标量变量上,而不是在标量值上。看起来它可以做到这一点。其目的是以惰性方式按需计算字符串,并根据需要对值执行一些昂贵的操作。我们的用户可能创造了许多价值,但最终只使用了少数价值。至少可以说,用户不是专家,所以如果我们能让它看起来像一个计划字符串,那就最好了。我会试试看,一会儿给你回复。效果很好!我已经调整了标题以更好地反映我的问题。我会删除你答案的前半部分。@bukzor=>你也可以看看我在CPAN上的模块List::Gen
,它包含一个相当健壮的惰性列表实现,似乎比我自己编写的要好。你用过吗?从文件中不清楚:$x/2是否返回另一个
use strict;
use warnings;
main();
sub GetThing{
return mything->new( shift );
}
sub main {
my %m;
$m{pre} = GetThing('Fred');
print "1\n";
print $m{pre};
print "2\n";
print $m{pre};
print "3\n";
}
package mything;
sub new {
my $class = shift;
bless {
name => shift || 'noname',
}, $class;
}
use overload '""' => sub { # '""' means to overload stringification
my $self = shift;
print "ACCESS ALERT!\n";
return " NAME: '$self->{name}'\n";
};