从方法添加 Moose 属性时“无法修改非左值子例程调用”

Bra*_*roy 4 perl attributes moose

这几天我在和Moose战斗,遇到了以下问题。我创建了一个对象,该对象在创建时具有许多必需的属性。但是,我希望在调用方法时向其添加属性。更具体地说,我想添加该方法的参数作为哈希属性。我想这样做,以便后续对其他方法的调用知道先前的方法已经使用所述参数被调用。

示例,但虚构的代码:

package Banana;

use Moose;

has ['peel', 'edible'] => (
  is  => 'ro',
  isa => 'Bool',
  required => 1,
);

has 'color' => (
  is  => 'ro',
  isa => 'Str',
  required => 1,
);

has 'grow_params' => (
  is  => 'ro',
  isa => 'HashRef',
);

sub grow {
  my ($self, $params) = @_;
  # params would be a hashref of method arguments
  $self->grow_params = $params;
  # Execute some code changing other, initial vars
}
Run Code Online (Sandbox Code Playgroud)

这不会起作用,因为会抛出以下错误:

无法修改非左值子例程调用&Banana::grow_params

我在这里查看了 SO 和 PerlMonks,但我似乎找不到该错误含义的一般解释。大多数答案只是重写原始代码,仅此而已。那么这个错误意味着什么,我可以完成我想要做的事情吗?或者这不是这样做的方法?

Dav*_*oss 5

详细解释一下该错误的含义......

基本的赋值语句如下所示:

$variable = 'value';
Run Code Online (Sandbox Code Playgroud)

运算符 ( ) 左侧的操作数$variable是“左值”。运算符 ( ) 右侧的操作数'value'是“右值”。

在上面的简单示例中,右值是一个简单的常量,但我希望您意识到它也可以是另一个变量:

$variable = $some_other_variable;
Run Code Online (Sandbox Code Playgroud)

甚至是表达式的结果:

$variable = 2 * $pi * $radius ** 2;
Run Code Online (Sandbox Code Playgroud)

但您知道(至少本能地)左值必须是一个变量。您知道这样的代码没有任何意义:

'value' = $variable;
Run Code Online (Sandbox Code Playgroud)

Moose 属性访问器和修改器(“getters”和“setters”)只是子例程。子程序通常是右值。这意味着您(通常)不能分配如下属性:

$obj->attribute = 'value';
Run Code Online (Sandbox Code Playgroud)

您需要将新值传递给该方法:

$obj->attribute('value');
Run Code Online (Sandbox Code Playgroud)

然而,有一个名为MooseX::LvalueAttribute 的Moose 扩展,它允许您定义左值变异器方法,这些方法完全按照原始代码的预期工作。但我真的不推荐它,因为这不是维护程序员期望在代码中看到的内容。