我想在修改对象的方法中使用重载运算符。我也希望在不重复代码的情况下实现它。
为了说明问题,我将展示我想要做的简化版本。在我的原始代码中,add
方法重载+
和complicated_calculation
方法尝试更新对象。
add
方法创建一个新的Number
对象,以避免像$n + 1
这样的表达式修改对象。
package Number;
use overload
'0+' => 'get_value',
'+' => 'add';
sub new {
my ($class, $value) = @_;
my $self->{value} = $value;
return bless($self, $class);
}
sub get_value {
my ($self) = @_;
return $self->{value};
}
sub set_value {
my ($self, $value) = @_;
$self->{value} = $value;
}
# Actual class has more attributes and the logic of addition includes branches.
sub add {
my ($self, $other) = @_;
print "add $other\n";
return Number->new($self->get_value + $other);
}
sub complicated_calculation {
my ($self) = @_;
# Do something complicated.
$self += 10;
}
package main;
my $n = Number->new(1);
print $n + 1 . "\n";
$n++;
print $n . "\n";
$n->complicated_calculation;
print $n . "\n";
将输出
add 1
2
add 1
2
add 10
2
我希望打印complicated_calculation
方法(12)的结果,而是打印2。 complicated_calculation
方法的结果设置为add
方法创建的对象,而不是调用它的对象。
我可以使用complicated_calculation
方法使add_in_place
方法更新对象以就地添加数字,但这需要add
和add_in_place
中的重复代码我被教导要避免。
在实际应用程序中,Number
类将具有更多属性,并且添加的代码将更长。
package Number;
use overload
'0+' => 'get_value',
'+' => 'add',
'+=' => 'add_in_place',
'fallback' => 1;
sub new {
my ($class, $value) = @_;
my $self->{value} = $value;
return bless($self, $class);
}
sub get_value {
my ($self) = @_;
return $self->{value};
}
sub set_value {
my ($self, $value) = @_;
$self->{value} = $value;
}
# Actual class has more attributes and the logic of addition includes branches.
sub add {
my ($self, $other) = @_;
print "add $other\n";
return Number->new($self->get_value + $other);
}
sub add_in_place {
my ($self, $other) = @_;
print "add_in_place $other\n";
$self->set_value($self->get_value + $other);
}
sub complicated_calculation {
my ($self) = @_;
# Do something complicated.
$self += 10;
}
package main;
my $n = Number->new(1);
print $n + 1 . "\n";
$n++;
print $n . "\n";
$n->complicated_calculation;
print $n . "\n";
将输出
add 1
2
add_in_place 1
2
add_in_place 10
12
我觉得应该有更好的方法,并希望得到你们的一些建议。
答案 0 :(得分:3)
首先,必须始终 use strict
和use warnings
位于您编写的每个 Perl程序文件的顶部。这尤其适用于您在寻求代码帮助时,因为它是防止错误的第一道防线,并且在困扰他人之前真的应该是您的第一手段。
这种情况正在发生,因为调用add
方法来实现+=
运算符,该运算符返回一个新的Number
对象。这会导致$self
中complicated_calculation
的值被更改为引用 new Number
对象,正确地,其值为12.但原始值为值 - 主代码中的$n
- 仍然指向值为2的对象。
要使其正常运行,您可以安排complicated_calculation
返回新对象,并且调用代码会将其分配给$n
。只需将该语句更改为
$n = $n->complicated_calculation
会让它发挥作用。
然而,将这样的东西写成一种方法有点奇怪。 Number
类中的代码应该专注于使对象行为正确,因此所有方法都应该是运算符。如果您在complicated_calculation
包中编写main
作为子例程,那么您可以使用
$n += 10;
print $n;
因为$n
的复制将正确且透明地工作。只有在编写方法时才重新分配$self
没有意义,因为它不再引用调用代码所使用的对象。
如果你真的认为complicated_calculation
是一个运算符,那么它应该就地改变对象,而不是依靠overload
来提供机制。如果您将其更改为
sub complicated_calculation {
my ($self) = @_;
$self->{value} += 10;
}
然后一切都会按预期工作。
<强>更新强>
我坚信你应该用add_in_place
来写一切,这应该是一个私人方法,只能在课堂内部使用。
add
和complicated_calculation
都可以非常简单地重写,并且不再需要编写$n = $n->complicated_calculation
,因为该方法可以就地修改对象。
该模块的示例代码演示了。
package Number;
use strict;
use warnings;
use 5.010;
use overload
'0+' => 'get_value',
'+' => 'add';
sub new {
my ($class, $value) = @_;
bless { value => $value };
}
sub get_value {
my ($self) = @_;
$self->{value};
}
sub set_value {
my ($self, $value) = @_;
$self->{value} = $value;
}
sub add {
my ($self, $other) = @_;
print "add $other\n";
Number->new($self->get_value)->add_in_place($other);
}
sub add_in_place {
my ($self, $other) = @_;
print "add_in_place $other\n";
$self->{value} += $other;
$self;
}
sub complicated_calculation {
my ($self) = @_;
$self->add_in_place(10);
}