Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
观察Perl类中属性的变化_Perl_Oop_Watch_Mojolicious_Moo - Fatal编程技术网

观察Perl类中属性的变化

观察Perl类中属性的变化,perl,oop,watch,mojolicious,moo,Perl,Oop,Watch,Mojolicious,Moo,有人能提供一个代码示例吗?如何在类内部设置变量更改的观察者?我尝试了几种使用不同特性(,)和OOP框架(Moo,Mojo::Base)的方法,但都失败了 下面是我的失败代码,以便更好地理解我的任务。在本例中,每当attr1发生更改时,我都需要更新attr2 使用Mojo::Base和Scalar::Watcher: package Cat; use Mojo::Base -base; use Scalar::Watcher qw(when_modified); use feature 'say'

有人能提供一个代码示例吗?如何在类内部设置变量更改的观察者?我尝试了几种使用不同特性(,)和OOP框架(Moo,Mojo::Base)的方法,但都失败了

下面是我的失败代码,以便更好地理解我的任务。在本例中,每当attr1发生更改时,我都需要更新attr2

使用Mojo::Base和Scalar::Watcher:

package Cat;
use Mojo::Base -base;
use Scalar::Watcher qw(when_modified);
use feature 'say';

has 'attr1' => 1;
has 'attr2' => 2;

has 'test' => sub { # "fake" attribute for getting access to $self
  my $self = shift;
  when_modified $self->attr1, sub { $self->attr2(3); say "meow" };
};


package main;
use Data::Dumper;

my $me = Cat->new;
$me->attr1;
warn Dumper $me;
say $me->attr1(3)->attr2; # attr2 is still 2, but must be 3
使用Moo和触发器:

package Cat;
use Moo;
use Scalar::Watcher qw(when_modified);
use feature 'say';

has 'attr1' => ( is => 'rw', default => 1, trigger => &update() ); 
has 'attr2' => ( is => 'rw', default => 1);

sub update {
  my $self = shift;
  when_modified $self->attr1, sub { $self->attr2(3); say "meow" }; # got error here: Can't call method "attr1" on an undefined value
};


package main;
use Data::Dumper;

my $me = Cat->new;
$me->attr1;
warn Dumper $me;
say $me->attr1(3)->attr2;
非常感谢您的任何建议。

Moo部分 此处出现错误:无法对未定义的值调用方法“attr1”

这是因为Moo希望代码引用作为
has的
触发器。您正在将调用的结果传递给
update
。这里的
&
没有提供参考,而是告诉Perl忽略
更新
函数的原型。你不会想要的

相反,用
\&foo
创建一个引用,不要添加括号
()
。您不想调用该函数,而是想引用它

现在,一旦完成了,就不再需要Scalar::Watcher了。触发器已经做到了这一点。每次更改
attr1
时都会调用它

sub update {
    my $self = shift;
    $self->attr2(3);
    say "meow";
};
如果现在运行整个程序,它会工作一点,但会因以下错误而崩溃:

无法通过包“3”定位对象方法“attr2”(可能您忘记加载“3”?)

这是因为
attr1
返回新值,而不是对
$self
的引用。所有Moo/Moose访问器都是这样工作的。而且
3
不是对象,因此它没有方法
attr2

#       this returns 1
#               |
#               V
say $me->attr1(3)->attr2;
相反,这是两个调用

$me->attr1(3);
say $me->attr2;
这里有一个完整的例子

package Cat;
use Moo;

use feature 'say';

has 'attr1' => ( is => 'rw', default => 1, trigger => \&update );
has 'attr2' => ( is => 'rw', default => 1 );

sub update {
    my $self = shift;
    $self->attr2(3);
    say "meow";
}

package main;
my $me = Cat->new;

say $me->attr2;
$me->attr1(3);
say $me->attr2;
以及输出:

1
meow
3
为什么Scalar::Watcher不能与Mojo一起工作 首先,Mojo::Base不提供触发机制。但是您实现Scalar::Watcher的方式无法工作,因为从未调用
test
方法。我尝试在基于Mojo::Base的类中挂起
new
,以便在总是调用它的地方进行
修改时调用

从这里开始的一切都只是猜测

下面的代码片段是我尝试过的,但它不起作用。我将在下面进一步解释原因

package Cat;
use Mojo::Base -base;
use Scalar::Watcher qw(when_modified);
use feature 'say';

has 'attr1' => '1';
has 'attr2' => 'original';

sub new {
    my $class = shift;

    my $self = $class->SUPER::new(@_);
    when_modified $self->{attr1}, sub { $self->attr2('updated'); say "meow" };

    return $self;
}
如您所见,这现在是
new
调用的一部分。代码确实会被执行。但这没用

结果是观察者应该在那里,直到变量超出范围

如果在void上下文中调用_modified,则观察者将 在$variable的生命周期结束前处于活动状态;否则,它将返回一个 对取消器的引用,用于在取消器被禁用时取消此观察程序 垃圾收集

但实际上我们没有标量变量。如果我们试着去做

when_modified $self->foo
然后Perl在
$self
上执行
foo
的方法调用,并且
当_modified
将获得该调用的返回值时。我还试着深入到上面这个对象的内部,但也没有成功


我的XS不够强大,无法理解正在发生的事情,但我认为它在连接魔法时遇到了一些问题。它无法处理哈希引用值。可能这就是它被称为Scalar::Watch的原因。

太好了,它可以工作,非常感谢您的详细解释!如果有人会回顾Mojo::Base+Scalar::Watcher部分,我会很高兴的。)现在我正在做一些架构决策,如果可能的话,我希望避免使用Moo或Moose作为不超重的应用程序。我正在努力。我不认为你能让它起作用。而且,它很贵。Scalar::Watcher的文档甚至说您应该只在调试时使用它。用Moo代替。它很轻。除非你在树莓上运行,否则你应该没问题。”如果你运行这个,它会工作一点,但会因为这个错误而崩溃:“这部分我花了一段时间才理解,因为看起来你仍然在谈论
更新
子例程,而你实际上指的是OP代码的
main
包中的调用代码。@Borodin我当时很匆忙。我稍后会说得更清楚。如果您愿意,可以随意编辑。Mojo::Base的一点是,它不应该是一个通用的对象系统。它提供了简单的行为,速度非常快。我们始终支持使用Moo(se)构建您的魅力应用程序?当你想要这样的行为,那就是最好的解决方案!
when_modified $self->foo