Moose: Array of Objects->loop through Attribute

2019-07-31 01:18发布

问题:

I'm new to Perl Moose, and I'm trying to achieve this simple task. I have my Moose class "TestObject" defined:

package TestObject;
use Moose;
use namespace::autoclean;

has 'Identifier' => (is =>'ro',isa=>'Str');

around BUILDARGS => sub
{
    my $orig = shift;
    my $class = shift;

    if ( @_ == 1 && ! ref $_[0] ) {
        return $class->$orig(Identifier => $_[0]);
    }
    else {
        return $class->$orig(@_);
    }
};
__PACKAGE__->meta->make_immutable;
1;

In another script I'm trying to access the attribute "Identifier" directly from an array of "TestObjects":

use TestObject;
use experimental 'smartmatch';
my @aArray1=(TestObject->new("z003"),TestObject->new("t302"),TestObject->new("r002"));
my $sIdent="t302";
if($sIdent~~@aArray1->Identifier)
{
    print "Element with Identifier".$sIdent." found.";
}

This doesn't work. I could implement a workaround like this:

my @aIdent=();
foreach my $sObject(@aArray1)
{
    push(@aIdent,$sObject->Identifier);
}
if($sIdent~~@aIdent)
{
    print "Element with Identifier".$sIdent." found.";
}

but that doesn't seem to be the most elegant solution. What is the most elegant solution to solve this problem?

回答1:

Do not do this with the smartmatch operator. It's experimental for a reason, and it might be removed from future Perl versions, or change the way it works, as it's done before.

Instead, this can be achieved with a simple grep.

my @aArray1 = ( 
    TestObject->new("z003"), 
    TestObject->new("t302"),
    TestObject->new("r002"),
);

my $sIdent = "t302";
if ( grep { $_->Identifier eq $sIdent } @aArray1 ) {
    print "Element with Identifier" . $sIdent . " found.";
}

If you want that to be a bit shorter, you can also use first from List::Util. This is a bit faster as it will stop looking after the first match.

use List::Util 'first';
my @aArray1 = ( 
    TestObject->new("z003"), 
    TestObject->new("t302"),
    TestObject->new("r002"),
);

my $sIdent = "t302";
if ( first { $_->Identifier eq $sIdent } @aArray1 ) {
    print "Element with Identifier" . $sIdent . " found.";
}

A few words of advice on your code:

  • Do not ever name a class anything with object. It is going to confuse you, future you and the maintenance guy. If you do not understand the difference between class and object, read up on that please.
  • Variable names and functions in Perl are always written in lower case by convention, and we use snake case. Camel case is reserved for package names.