简体   繁体   中英

perl: Can't use string as an ARRAY ref while “strict refs” in use

I have this problem where I'm trying to pass an array to a sub and it reads some other value. In this test script I'm passing a reference of array @players but its reading string $buffer instead.

use Data::Dumper;

my @players = [];
my @playerscores = [];
my %FORM;

my $buffer = "numplayers=2&changeplayers=3&CHANGEIT=CHANGEIT&player1=a&player2=b&restart=1&newcoords=";

sub testsub {
    my @testee = @$_[0];
    print "in testsub: $testee[0]\n";
}

my @holder = split(/&/,$buffer,);
foreach my $iter (@holder)
{
    my ($name,$value) = split(/=/,$iter);
    $FORM{$name} = $value;
}
$_ = $buffer;
foreach my $key (keys(%FORM))
{
    if($key=~ /player[1-9]/)
    {
        if(!($FORM{$key} eq ""))
        {
            my $holder = $key;
            $holder =~ s/player//;
            $players[$holder] = $FORM{$key};
            $playerscores[$holder] = 0;
            $_ = $buffer;
        }
    }
}

print "\n Data Dumper on player:\n";
print Dumper(@players);
print "\n\n";

print "Check sub:\n";
testsub(\@players,\@playerscores);

output:

 Data Dumper on player:
$VAR1 = [];
$VAR2 = 'a';
$VAR3 = 'b';


Check sub:
Can't use string ("numplayers=2

&changeplayers=3&CHA"...) as an ARRAY ref while "strict refs" in use at test-str-pool2.pl line 15.

Whereas I was expecting "a" or "b" as the result of print "in testsub: $testee[0]\\n"; . Why is this happening?

You're declaring your arrays wrongly which is why the Dumper output has [] (an empty array reference) as the first element in @players . Use:

my @players = ();
my @playerscores = ();

The second error comes from:

my @testee = @$_[0];

This attempts to dereference $_ and take the first element from the resulting array. You mean:

my @testee = @{$_[0]};

Which takes the first element from @_ and dereferences it.

There are several things you're doing wrong.

You have player1 and player2 . You are using an array to hold them, and removing the player string to get the player number.

There is no player0 which is why you're getting an undef in the first value of your array.

You are passing in two array references, but only looking at one, and looking at it in the wrong way too:

I prefer to do this:

sub testsub {
    my $testee_ref = shift;
    @testee = @{ $testee_ref };

I like using shift because it's more obvious what you're doing. I would prefer to use a two step approach (get the reference, then dereference that dereference). But, you could also use:

sub testsub {
    my @testee = @{shift()};

or

sub testsub {
    my @testee = @{$_[0]};   #Take the reference in $_[0] and dereference it.

Either way, you now get the error message:

Use of uninitialized value $testee[0] in concatenation (.) or string at ./test.pl line 40.

Because your the first element in your array is undefined!

It looks like you want to store the information about the player and their score in an easily accessible format. I would use a single reference to keep the player's score , their name , and all aspects of their game together in one place. You're already know about references because you're using them:

#!/usr/bin/env perl
use strict;
use warnings;
use feature qw(say);
use Data::Dumper;

my $game = {};   # A reference to a game
$game->{PLAYERS} = {}; # A reference to the players
my $buffer = "numplayers=2&changeplayers=3&CHANGEIT=CHANGEIT&player1=a&player2=b&restart=1&newcoords=";

for my $values ( split /&/, $buffer ) {
    my ($key, $value ) = split /=/, $values;
    if ( $key !~ /^player/ ) {
        $game->{$key} = $value;
    }
    else {
        $game->{PLAYERS}->{$key}->{NAME} = $value;
        $game->{PLAYERS}->{$key}->{SCORE} = 0;
    }
}

say Dumper $game;

# Dumper a player
#

for my $player ( sort keys %{ $game->{PLAYERS} } ) {
    testsub( $game->{PLAYERS}->{$player} );
}

sub testsub {
    my $player_ref = shift;
    say "Player Name = " . $player_ref->{NAME};
    say "Player Score = " . $player_ref->{SCORE};
}

Running this will give you:

$VAR1 = {
        'newcoords' => '',
        'restart' => '1',
        'changeplayers' => '3',
        'numplayers' => '2',
        'PLAYERS' => {
                        'player2' => {
                                        'NAME' => 'b',
                                        'SCORE' => 0
                                    },
                        'player1' => {
                                        'NAME' => 'a',
                                        'SCORE' => 0
                                    }
                    },
        'CHANGEIT' => 'CHANGEIT'
        };

Player Name = a
Player Score = 0
Player Name = b
Player Score = 0

Note that I have a single variable called $game that stores all of the information about the game including all of the player information. Now, if I am given a reference to a player, I can print out that player's name and score.

Even better would be using Object Oriented Perl . All OOPerl does is use subroutines and blessing of references to manager these complex object types for you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM