Perl嵌套数组、哈希和引用。

3

我已经尝试了各种@%$的组合,但我无法使其正常工作。整个表达式可以工作,但是我该如何将其拆分为变量?

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 的思维方式 :(. 非常感谢任何帮助。


2
快速(但必要)阅读参考资料,让您开始学习:https://perldoc.perl.org/perlreftut - Dada
尝试使用 my %col = %{$cols->[1]} 替换代码行 "my %col = %cols[1];" - Håkon Hægland
2
我已经尝试了各种@%$的组合。我最喜欢这个问题的地方在于它看起来像你正在审查脏话,但实际上你只是准确地描述了Perl语法。 - Silvio Mayolo
@Data 是的,那个参考资料非常好,帮我找到了答案。谢谢。 - Tuntable
4个回答

3
您可以使用模块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';

正如您所看到的,您实际上有一个嵌套数组。因此,您需要先访问嵌套数组,然后再访问哈希表。


咦?它怎么变成嵌套的了?还需要什么咒语才能解除嵌套?[0]没有帮助。$%@到底是什么?它们有点像语法噪音,但也有点像改变语义的运算符。我称它们为“珍珠”。谢谢。 - Tuntable
代码相关内容的翻译:它嵌套在这里: my @cols = $tables{"grp"}; 基本上,你要创建一个新数组,在其中添加来自%tables散列表的数组。可以使用以下代码查看:print "Inside tables", Dumper($tables{"grp"}),"\n"; 现在只有一个带哈希的单个数组了。 - Ivan Dimitrov
你可以通过以下方式解嵌套它:`my @arr = map {$_->[0]} @cols;print Dumper(@arr);` 这将打印数组的第一个元素,也就是你想要的数组。 - Ivan Dimitrov

1
以下是示例演示代码,提供了OP所称的数据库“shema”形成的众多可能方式之一。
在函数addColumn($name, $type)中,OP没有指定列属于哪个表。
很好地看到OP期望建立什么最终数据结构来澄清最终结果将是什么,这将是很好的。
提供示例代码,希望它能帮助OP找到解决问题的方法。
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中面向对象编程的内容,这将允许封装表格数据/结构到一个对象中。结果代码看起来更加清晰易懂,更容易维护。
伪代码示例
......
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');
.....

OP使用全局变量来存储当前表($columns),以使调用更加简洁,并且根据Dumper生成了正确的结构。虽然可以使用不同的风格,但您没有回答我的问题,即如何索引所创建的结构。(我也不理解您的花哨的push,但这不是问题所在。) - Tuntable
您可以通过如下结构访问 $tables{$tbname}{columns}[$index]{$key} 中的内容(或者,如果 key 仅包含单个单词,则可以使用 $tables{'grp'}{'columns'}[0]{'name'} )。$tables{$tbname}{columns} 是一个 arrayref 数组引用,您不能直接向其 push 元素,因为它需要被解引用为 @{$arrayref} - Polar Bear
@Tuntable 我已经编辑了你的问题,并添加了附录,演示了对存储数据的访问,尽管根据你的代码示例创建数组/哈希的副本(在这种特定情况下是不必要的,因为复制会占用内存和CPU周期)。如果你不需要重复的数据,那么可以通过引用数组/哈希来实现访问——它更快,不消耗内存并节省CPU周期。 - Polar Bear
1
@PolarBear 我已经撤销了你对问题的编辑。你添加的代码没有任何解释,而且这段文字应该放在答案中而不是问题中。请记住,如果您想要,可以发布多个答案。 - Dada
@Dada - 对我来说没问题,我不再关心这个问题了。 - Polar Bear

0

%cols[1]语法是一个索引值数组切片。如果@cols只有一个元素,则索引1处的值未定义,%cols[1]将返回列表(1, undef),该列表被分配给第一个代码片段中第4行的%col

my %col = %cols[1];

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

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

它试图打印键“1”与值undef连接在一起,这会产生一个警告,然后输出:

Use of uninitialized value in print
COLvar 1

什么?$cols[1]不起作用。那么如何不执行片段操作,而是执行简单的索引操作? - Tuntable
@Tuntable 在这种情况下,$#cols == 0,因此$cols[1]不存在。我不确定您所说的“不起作用”是什么意思。请澄清。 - Håkon Hægland

0

感谢您的帖子,但它们都没有解决实际问题。解决方案是:

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} 是解引用运算符。

我仍然不太明白 "%" 等符号的作用。我认为最好只使用引用并完全避免使用 % 和 @。

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


在继续查看该视图之前,请确保还查看了Perl文档的另一部分,即有关Perl变量的部分:https://perldoc.perl.org/perlvar。 - Bruce Van Allen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接