“Can't modify non-lvalue subroutine call” when adding Moose attribute from method

守給你的承諾、 提交于 2020-01-24 20:05:09

问题


I am battling with Moose these days, and I ran into the following problem. I create an object that has many required attributes on its creation. However, I wish to add attributes to it when a method is called. More specifically, I'd like to add the arguments for that method as a hash attribute. I'd like to do this so that subsequent calls to other methods know that the earlier method has already been called, with said parameters.

Example, but fictional code:

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
}

This won't work, as the following error gets thrown:

Can't modify non-lvalue subroutine call of &Banana::grow_params

I've looked here on SO and on PerlMonks but I can't seem to find a general explanation of what the error means. Most answers simply re-write the original code and that's that. So what does the error mean, and can I accomplish what I'm trying to do? Or is this not the way to do it?


回答1:


Moose object attributes are hidden behind functions of the same name, so when you have $self->grow_params that's a function. Trying to assign a value to it won't work, you need to call it like a function.

$self->grow_params($params);

But even then, as you've currently defined grow_params as read only, you can't change it's value once the object has been created, even within it's own methods.




回答2:


To explain a little more about what the error means...

A basic assignment statement looks like this:

$variable = 'value';

The operand to the left of the operator ($variable) is an "lvalue". The operand to the right of the operator ('value') is an "rvalue".

In the simple example above, the rvalue is a simple constant, but I hope you realise that it could also be another variable:

$variable = $some_other_variable;

or even the result of an expression:

$variable = 2 * $pi * $radius ** 2;

But you know (instinctively, at least) that the lvalue has to be a variable. You know that code like this makes no sense:

'value' = $variable;

Moose attribute accessors and mutators (the "getters" and "setters") are just subroutines. And subroutines are usually rvalues. This means that you can't (usually) assign an attribute like this:

$obj->attribute = 'value';

You would need to pass the new value to the method:

$obj->attribute('value');

However, there is a Moose extension called MooseX::LvalueAttribute which allows you to define lvalue mutator methods that work exactly how your original code expected them to. I really don't recommend it though, as it's not what maintenance programmers will expect to see in your code.



来源:https://stackoverflow.com/questions/45276597/cant-modify-non-lvalue-subroutine-call-when-adding-moose-attribute-from-metho

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!