OOP Perl pasando @_ al segundo método

#! /usr/bin/perl

# this is the object tester

{package Hate;
sub status {
my $class = shift;
print "-- $_[0] $_[1] $_[2]\n";
print "$class exists and ", $class->stats($_[0]), "and ", $class->type($_[1]), "and ",     $class->location($_[2]);
}
}

{package Grudge;
@ISA = "Hate";
sub stats{"$_[0]\n"}
sub type{"$_[0]\n"}
sub location{"$_[0]\n"}
}

Hate::status("Grudge", @ARGV);

i ran ./program one two three

this output is what i expected Grudge exists and one and two and three

this is what i got Grudge exists and Grudge and Grudge and Grudge

However when i use this script

#! /usr/bin/perl

# this is the object tester

{package Hate;
sub status {
my $class = shift;
print "-- $_[0] $_[1] $_[2]\n";
print "$class exists and ", $class->stats($_[0]), "and ", $class->type($_[1]), "and ",     $class->location($_[2]);
}
}

{package Grudge;
@ISA = "Hate";
sub stats{"$_[1]\n"}
sub type{"$_[1]\n"}
sub location{"$_[1]\n"}
}

Hate::status("Grudge", @ARGV);

Esto funcionó.

preguntado el 01 de julio de 12 a las 18:07

Do you Hate or have a Grudge against indenting code and capitalization in sentences? -

I really am not trying to sounds snide, but why do you expect one two three? Perhaps if you explain why this is your expectation we might understand what the disconnect is. Also what is in @ARGV? -

1 Respuestas

En tu primer ejemplo, $class->stats($_[0]) se llama como Método and is passed an object as the first argument, which needs to be shifted away as you did in Hate::status. Es por eso $_[1] works: because the first argument to the method is actually the second item in @_ (después $self).

Things become a lot more clearer, and manageable, if you unpack arguments out of @_ at the beginning of the function, e.g.

{
    package Hate;
    sub status {
        my ($class, $stats, $type, $location) = @_;
        print "-- $stats $type $location\n";
        print "$class exists and ", $class->stats($stats), ...;
    }
}

{
    package Grudge;
    our @ISA = qw(Hate);
    sub stats { my ($self, $stats) = @_; $stats; }
    sub type { my ($self, $type) = @_; $type; }
    sub location { my ($self, $location) = @_; $location; }
}

Hate::status('Grudge', @ARGV);

As a side note, your use of objects is not typical - if you provided more code, we may be able to provide a more idiomatic Perl solution. For example, none of your objects have constructors, and at the moment the three Grudge methods appear to do the same thing. It's also not clear why Grudge es una subclase de Hate (como lo indica el @ISA).

si realmente no quieres Grudge to be passed its own name as an argument you can call its methods as functions via &{$class . '::stats'}() but you will have to disable strict subs. It's generally better to call methods as you are doing now.

Respondido 01 Jul 12, 18:07

I usually get around method invokation by doing my $method = $class->can('stats') entonces cuando llamas $method->(@args) it doesn't pass the self-reference. Cleaner and strict-safe. ;-) - Joel Berger

@JoelBerger: Yeah, but even so, why would you want to? - ilmari karonen

Ok, truth be told, I don't avoid method invokation, I need references to methods, and I call them with $method->($instance, @args), but the usage isn't any different. Why @rjh does this I don't know. - Joel Berger

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.