嵌套的 perl 数组和散列和引用

Nested perl arrays and hashes and references

我已经尝试了@%$s 的各种组合,但我无法让它工作。完整的表达式有效,但如何将其拆分为变量?

print "BIGexp ", $tables{"grp"}[1]{_name}, "\n"; # OK, prints part
my @cols = $tables{"grp"};
print "COLS ", @cols, "\n"; # prints array
my %col = %cols[1]; 
print "COLvar ", %col, " ", "\n"; #prints 1 ?
print "COLexp ", $cols[1]{_name}, "\n";  ######## Fails, uninitialized.

我想表示数据库模式。所以一个表的映射,每个表包含一个列数组,每个列都是一个映射。这是完整的片段。

my %tables=();

my $columns; # array

sub addTable {
  my @cols = ();
  $tables{$_[0]} = \@cols;
  $columns = \@cols;
}

sub addColumn {
    my %col  = (_name => $_[0],  _typ => $_[1]);
    push(@$columns , \%col);
}

addTable("grp");
addColumn("id", "serial");
addColumn("part", "integer");

addTable("tab2");
addColumn("foo2", "varchar");
addColumn("bar2", "integer");

print "BIGexp ", $tables{"grp"}[1]{_name}, "\n"; # OK, prints part
my @cols = $tables{"grp"};
print "COLS ", @cols, "\n"; # prints array
my %col = %cols[1]; 
print "COLvar ", %col, " ", "\n"; #prints 1 ?
print "COLexp ", $cols[1]{_name}, "\n";  ######## Fails, uninitialized.

我是 Perl 的新手,还没有成为“Perl 头脑”:(。非常感谢任何帮助。

语法 %cols[1] 是一个 index-value array slice。如果 @cols 只有一个元素,则索引 1 处的值未定义,并且 %cols[1] returns 列表 (1, undef) 在第 4 行分配给 %col你的第一个片段:

my %col = %cols[1];

所以现在 %col = ("1" => undef) 当您尝试在第 5 行打印它时:

print "COLvar ", %col, " ", "\n";

它尝试打印与值 undef 连接的键“1”,它发出警告,然后输出:

Use of uninitialized value in print
COLvar 1

以下示例演示代码提供了多种可能的方法之一来形成 OP 命名为数据库 shema.

函数 addColumn($name, $type) 中的 OP 没有指定 table 列属于什么。

很高兴看到 OP 期望构建 的最终数据结构,以阐明最终结果。

提供示例代码,希望它能帮助 OP 找到 his/her 问题的解决方案。

use strict;
use warnings;
use feature 'say';

use Data::Dumper;

my %tables;

tbAddColumn('grp','id','serial');
tbAddColumn('grp','part','integer');

tbAddColumn('tab2','foo2','varchar');
tbAddColumn('tab2','bar2','integer');

say Dumper(\%tables);

my $tb_name = 'grp';

say "Table: $tb_name";
say '-' x 45;

for my $column ( @{$tables{$tb_name}{columns}} ) {
    say "name => $column->{name}, type => $column->{type}";
}

exit 0;

sub tbAddColumn {
    my $tbname = shift;
    my $name   = shift;
    my $type   = shift;

    push @{$tables{$tbname}{columns}}, { name => $name, type => $type};
}

输出

$VAR1 = {
          'tab2' => {
                      'columns' => [
                                     {
                                       'name' => 'foo2',
                                       'type' => 'varchar'
                                     },
                                     {
                                       'name' => 'bar2',
                                       'type' => 'integer'
                                     }
                                   ]
                    },
          'grp' => {
                     'columns' => [
                                    {
                                      'name' => 'id',
                                      'type' => 'serial'
                                    },
                                    {
                                      'type' => 'integer',
                                      'name' => 'part'
                                    }
                                  ]
                   }
        };

Table: grp
---------------------------------------------
name => id, type => serial
name => part, type => integer

注意:OP 可以在 Perl 中对 object oriented programming 做一些阅读,这将允许将 table data/structure 封装到一个对象中。结果代码看起来更清晰,更易于维护。

伪代码示例

......
my $tb1 = new dbTable('grp');
my $tb2 = new dbTable('tab2');

$tb1->addColumn('id','serial');
$tb1->addColumn('part','integer');


$tb2->addColumn('foo2','varchar');
$tb2->addColumn('bar2','integer');
.....

您可以使用模块 use Data::Dumper; 来打印您的数据结构。

print "BIGexp ", $tables{"grp"}[1]{_name}, "\n"; # OK, prints part
my @cols = $tables{"grp"};
print "COLS ", @cols, "\n"; # prints array
my %col = %cols[1]; 
print "COLvar ", Dumper(\%col), " ", "\n"; #prints 1 ?
print "COLexp ", Dumper(\@cols), "\n";  ######## Fails, uninitialized.

print "COLexp ", Dumper($cols[0][1]{_name}), "\n";

输出如下:

   BIGexp part
COLS ARRAY(0x800e5f480)
COLvar $VAR1 = {
          '1' => undef
        };
 
COLexp $VAR1 = [
          [
            {
              '_typ' => 'serial',
              '_name' => 'id'
            },
            {
              '_name' => 'part',
              '_typ' => 'integer'
            }
          ]
        ];

COLexp $VAR1 = 'part';

如您所见,您实际上有一个嵌套数组。所以你需要先访问嵌套数组,然后再访问散列。

感谢您的帖子,但其中 none 解决了实际问题。解决方案是

print "BIGexp ", $tables{"grp"}[1]{_name}, "\n"; # OK, part
my $cols = $tables{"grp"};  # ref array
my $col = ${$cols}[1];  # ref hash
my %colh = %{$col}; # hash
print "COLvar ", $colh{_name}, " ", "\n"; # bingo
print "COLvar2 ", ${$col}{_name}, " ", "\n"; # bingo
print "COL-> ", $col->{_name}, " ", "\n"; # bingo

诀窍在于处理引用数组和数组等之间的区别。{$x} 是取消引用运算符。

我还是不太明白“%”等到底是干什么的。我怀疑最好只使用引用并完全避免使用 % 和 @。

这个 link 非常有帮助 https://perldoc.perl.org/perlreftut