Хорошо, у меня есть следующая функция-член:
sub GetCategories {
my $sth = $dbh->prepare("SELECT CatID, CatName, CatLink FROM Categories");
$sth->execute() or die $DBI::errstr;
my $results = $sth->fetchall_arrayref({});
return($results);
$sth->finish();
}
Я называю это с помощью:
my $Cats = $d2s->GetCategories();
my $vars = my $vars = {
categories => $Cats,
};
Однако мой вопрос: как мне это детализировать и извлечь значения в Perl?
Это сводит меня с ума — ниже приведен формат данных $vars из Data::Dumper —
$VAR1 = {
'categories' => \[
[
1,
'General',
'./PostList.pl?cat=General'
],
[
2,
'DevOps',
'./PostList.pl?cat=DevOps'
]
};
Я ожидал увидеть
'categories' => [ { 'CatID' => 1, 'CatLink' => './PostList.pl?cat=General',
'CatName' => 'General' }, { 'CatID' => 2, 'CatLink' => './PostList.pl?cat=DevOps', 'CatName' => 'DevOps' },
и так далее
как мне, например, распечатать значение DevOps во второй структуре в Perl-скрипте. Я могу сделать это в шаблоне tt, но не в Perl.
Показанный вами код не дает показанного вами результата. Вы действительно передали пустой хеш-ссылку в качестве аргумента, например fetchall_arrayref({})
? Это должно возвращать одну хэш-ссылку на строку. Также ваш вывод Dumper показывает ссылку на ссылку на массив. Ваш код этого не дает.
Если переменная содержит ссылку, вам необходимо разыменовать ее, чтобы получить доступ к объекту, на который указывает ссылка.
my $VAR1 = {
categories => \[
[
1,
'General',
'./PostList.pl?cat=General'
],
[
2,
'DevOps',
'./PostList.pl?cat=DevOps'
]
] # <- this was missing in your code!
};
print ${ $VAR1->{categories} }->[1][1]; # DevOps
$VAR1 — это ссылка на хэш, мы можем разыменовать ее, используя стрелку.
$VAR1->{categories}
Значение, связанное с «категориями», является ссылкой на ссылку на массив, поэтому нам нужно разыменовать его как скаляр, чтобы получить ссылку на массив.
${ $VAR1->{categories} }
тогда мы сможем снова использовать стрелку, чтобы попасть в массив.
${ $VAR1->{categories} }->[1]
Кстати, если $sth->finish();
стоит после return
, он никогда не будет выполнен.
«Значение, связанное с «категориями», является ссылкой на ссылку на массив, поэтому нам нужно разыменовать его как скаляр, чтобы получить ссылку на массив». Это именно то, что я не знаю, как сделать. У вас есть пример того, как это сделать? Кстати: я изучаю Perl всего меньше месяца, но пишу сценарии Bash уже давно, и до сих пор мне нравится Perl.
Это показано в последней строке примера кода. О ссылках читайте в очень коротком руководстве Марка о ссылках и Perl-ссылках и вложенных структурах данных
Код, который вы показываете для GetCategories()
, предназначен для возврата массива ссылок Hashrefs. Обратите внимание на использование пустой хеш-ссылки в качестве аргумента fetchall_arrayref({})
, что описано здесь (если $slice является хэш-ссылкой, fetchall_arrayref извлекает каждую строку как хэш-ссылку). Однако остальная часть вашего вопроса показывает структуру, которая не была создана этим кодом.
Вот полный пример, демонстрирующий использование fetchall_arrayref({})
и способ доступа к определенному элементу в возвращаемой структуре (извините, это postgres, но здесь это не имеет значения):
use 5.030;
use warnings;
use Data::Dumper;
use DBD::Pg;
my $sql =q|
SELECT * FROM
(VALUES( 1,
'General',
'./PostList.pl?cat=General'),
( 2,
'DevOps',
'./PostList.pl?cat=DevOps')
)AS categories("CatID", "CatName", "CatLink")|;
my $dh = DBI->connect(
"DBI:Pg:dbname=postgres; host=127.0.0.1", "postgres");
die $DBI::errstr unless $dh;
my $sth = $dh->prepare($sql);
$sth->execute();
my $res = $sth->fetchall_arrayref({});
my $vars = {categories => $res};
print Dumper $vars;
#access CatName of 2nd row:
say $vars->{categories}[1]{CatName};
принты:
$VAR1 = {
'categories' => [
{
'CatLink' => './PostList.pl?cat=General',
'CatName' => 'General',
'CatID' => 1
},
{
'CatLink' => './PostList.pl?cat=DevOps',
'CatName' => 'DevOps',
'CatID' => 2
}
]
};
DevOps
Хорошее объяснение (думаю, вы имели в виду use DBI
, а не use DBD::Pg
)
Я использовал DBD::Pg, который использует DBI, но, как я уже писал, это пример pg, он также будет работать с MySQL.
Интересный. Я всегда следил за документами DBI и DBD::Pg, которые предполагают следующее: use DBI; $dbh = DBI->connect("dbi:Pg:dbname=$dbname", ...); # OR $dbh = DBI->connect("dbi:SQLite:dbname=$dbname", ...)
Это должно работать в любом случае. За исключением случаев, когда вы use DBI
он умрет во время выполнения, когда DBD::Pg не установлен. С use DBD::Pg
он умирает во время компиляции - здесь это не имеет значения.
Я попробую это позже.
Я добился того, что мне нужно, следующим образом, но это не идеально. Как только я разберусь со ссылками на Perl и областью видимости переменных, я последую вашему совету, потому что он выглядит более компактным и универсальным, а это то, чего я хочу.
$sth->execute() or die $DBI::errstr;
my @arrRtn;
my $i=0;
while ( my @row = $sth->fetchrow_array ) {
my ($cat_id, $cat_name, $cat_link ) = @row;
@arrRtn[$i] = {
'CatID' => $cat_id,
'CatName' => $cat_name,
'CatLink' => $cat_link,
};
$i++;
}
$sth->finish();
#print Dumper(@hRtn);
foreach (@arrRtn)
{
print "ID: $_->{'CatID'}<br>NAME: $_->{'CatName'}<br>LINK: $_->{CatLink}<br><br>";
}
Если вы
return
из подпрограммы, последняя строка$sth->finish()
никогда не выполняется. Возврат должен быть последней строкой в вашем субтитуле (в данном случае). Кроме того, ваш код содержит странные обратные кавычки. Если этого нет в вашем реальном коде, этого не должно быть в этом коде. Исправьте это, если это опечатка.