Perl: Нельзя использовать строку в качестве ARRAY ref при использовании "строгих ссылок"

У меня есть эта проблема, когда я пытаюсь передать массив в sub, и он читает другое значение. В этом тесте script я передаю ссылку массива @players, но вместо этого его вместо строки $string.

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);

выход:

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.

В то время как я ожидал "a" или "b" в результате print "in testsub: $testee[0]\n";. Почему это происходит?

2 ответа

Вы неправильно заявляете свои массивы, поэтому вывод Dumper имеет [] (пустую ссылку на массив) как первый элемент в @players. Использование:

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

Вторая ошибка возникает из:

my @testee = @$_[0];

Это попытка разыменовать $_ и взять первый элемент из результирующего массива. Вы имеете в виду:

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

Что берет первый элемент из @_ и разыгрывает его.


Есть несколько вещей, которые вы делаете неправильно.

У вас есть player1 и player2. Вы используете массив для их хранения и удалите строку player, чтобы получить номер игрока.

Нет player0, поэтому вы получаете undef в первом значении вашего массива.

Вы передаете две ссылки на массив, но смотрите только на один и смотрите на него неправильно:

Я предпочитаю это делать:

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

Мне нравится использовать shift, потому что это более очевидно, что вы делаете. Я бы предпочел использовать двухэтапный подход (получить ссылку, а затем разыменовать разыменование). Но вы также можете использовать:

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

или

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

В любом случае вы получите сообщение об ошибке:

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

Поскольку ваш первый элемент в вашем массиве undefined!

Похоже, вы хотите хранить информацию об игроке и их счет в легкодоступном формате. Я бы использовал одну ссылку, чтобы держать игрока, его имя и все аспекты их игры вместе в одном месте. Вы уже знаете о ссылках, потому что используете их:

#!/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};
}

Выполнение этого даст вам:

$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

Обратите внимание, что у меня есть одна переменная с именем $game, которая хранит всю информацию об игре, включая всю информацию о игроке. Теперь, если мне дается ссылка на игрока, я могу распечатать имя и счет игрока.

Еще лучше использовать Object Oriented Perl. Все OOPerl - это использование подпрограмм и благословение ссылок для управления этими сложными типами объектов для вас.

licensed under cc by-sa 3.0 with attribution.