Perl 哈希值的基本原理
Posted
技术标签:
【中文标题】Perl 哈希值的基本原理【英文标题】:Perl hash of hashes rationale 【发布时间】:2021-06-08 04:33:44 【问题描述】:我决定尝试 Perl,我偶然发现了一种似乎有效的语言结构,但我简直不敢相信它是有效的。我想这背后有一些理由,所以我决定问一个问题。
获取以下 Perl 代码:
%data = ('John Paul' => ('Age' => 45), 'Lisa' => 30);
print "\$data'John Paul' = $data'John Paul''Age'\n";
print "\$data'Lisa' = $data'Lisa'\n";
我的目的是检查哈希的哈希是如何工作的。上面的代码打印:
$data'John Paul' =
$data'Lisa' =
要使其成为一个有效的哈希散列,需要:
%data = ('John Paul' => 'Age' => 45, 'Lisa' => 30);
结果是:
$data'John Paul' = 45
$data'Lisa' = 30
有谁知道:
-
为什么不统一,内部哈希需要
而不是()
?
当内部散列使用()
而不是
时,为什么我没有收到错误或警告?很容易犯这样的错误。更重要的是,('Age' => 45)
不仅破坏了 'John Paul'
的值,还破坏了 'Lisa'
的值。我无法想象在数千行代码的项目中寻找这种“错误”。
【问题讨论】:
括号仅表示 Perl 中的列表分组和优先级。他们从不创造任何东西。例如(1, 2, 3)
等同于(1, (2, 3)
等同于(((1), ((2, (3)))))
等等。他们做的唯一真正的功能就是开始一个列表。
要验证您放入数据结构的内容,请使用 Data::Dump (以及许多其他选项)将其转储。 use Data::Dump "pp"; pp \%data;
【参考方案1】:
( 'John Paul' => ( 'Age' => 45 ), 'Lisa' => 30 )
只是另一种写作方式
'John Paul', 'Age', 45, 'Lisa', 30
Parens 不会创建任何数据结构;它们只会影响(3+4)*5
中的优先级。我们不写的原因
my %h = a => 4;
或同等的
my %h = 'a', 4;
是不是会被解释为
( my %h = 'a' ), 4;
创建哈希的是my %data
,而不是括号。赋值的右侧只是在堆栈上放置任意数量的标量,而不是散列。赋值运算符将这些标量添加到哈希中。
但有时,我们想创建一个匿名哈希。这就是 的用武之地。
my %data = ( 'John Paul' => 'Age' => 45 , 'Lisa' => 30 );
基本上等价于
my %anon = ( 'Age' => 45 );
my %data = ( 'John Paul' => \%anon, 'Lisa' => 30 );
请注意,\%anon
返回标量,即对哈希的引用。这与( 'John Paul' => \%anon, 'Lisa' => 30 )
和'John Paul' => \%anon, 'Lisa' => 30
返回的四个 标量有着根本的不同。
为什么不统一,内部哈希需要
而不是
()
?
这个问题的一个基本前提是错误的:哈希不需要()
。例如,以下是完全有效的:
my %h1 = 'm'..'p';
sub f return x => 4, y => 5
my %h2 = f();
my %h3 = do i => 6, j => 7 ;
()
与哈希无关。缺乏统一性源于缺乏平行性。一个使用 创建一个哈希。使用
()
覆盖优先级。
由于括号只会影响优先级,因此可以使用
my %data = ( 'John Paul' => ( 'Age' => 45 ), 'Lisa' => 30 ); # ok (but weird)
这与以下内容大不相同:
my %data = ( 'John Paul' => ( 'Age' => 45 ), 'Lisa' => 30 ); # XXX
当内部哈希使用 () 而不是 时,为什么我没有收到错误或警告?
不仅使用()
有效,通常还需要在包含逗号的表达式周围使用()
。那么它究竟应该在什么时候发出警告呢?关键是这是否应该是警告还是perlcritic
发现的东西是有争议的,至少乍一看是这样。后者肯定会找到这个,但我不知道它是否存在规则。
【讨论】:
次要。my %data
本身并不创建散列,它告诉 Perl 在范围和存储方面要创建哪种散列。定义散列的方法有很多种,所有这些方法都会创建一个散列,并且您可以创建一个从不与散列变量关联的匿名散列。通过引用它来创建一个哈希。
@lordadmira,关于“my %data
本身不会创建哈希”,它会。 my
具有编译时和运行时效果。 my %hash
的编译时效果是创建一个哈希,它的运行时效果是在范围退出时导致哈希被清除或替换为新的哈希。您可以使用
创建一个匿名哈希,或者您可以通过简单地提及其名称来创建一个全局哈希,这一事实并没有改变。
为什么它会在编译时创建一个变量,只是在进入范围后将其丢弃并创建一个新变量? my()
的重点是让 Perl 在遇到语句时自动激活词汇垫上的变量,然后捕获对该符号的所有引用作为对垫的引用。唯一的编译时影响是将符号合法化为strict
。
@lordadmira,Re“为什么它会在编译时创建一个变量,只是在进入范围后将其丢弃并创建一个新变量??”,它没有不。我说过当范围退出时它可以创建一个新的哈希。 /// Re "my()的目的是让Perl自动存活",你好像没理解"auto"的意思。如果您明确使用指令 (my
) 来执行此操作,则它不是自动的。自动激活是在您取消引用未定义的变量时自动创建变量和对它们的引用。【参考方案2】:
为什么不统一,内部哈希需要而不是()?
对哈希的赋值是一个标量列表(在键和值之间交替)。
您不能将哈希值(因为它不是标量)作为值,但您可以有哈希引用。
列表被展平。
当内部哈希使用 () 而不是 时,为什么我没有收到错误或警告?
因为您没有使用 the use strict; use warnings;
pragmas 将它们打开(默认情况下由于可怕的向后兼容性而关闭,但它将是 on by default in Perl 7)。
【讨论】:
那么打破'Lisa'
的价值呢?
a=>b
一个标量值 (a=>b)
两个标量值...见perldoc.perl.org/perlreftut
@AlBundy — Lisa 没有价值,列表变得扁平。 Lisa 是键 45 的值。
严格和警告都没有捕捉到这一点(尽管它们确实捕捉到了给出的具体示例中的奇数个元素)。不过,perlcritic
规则可能存在。 (如果没有,可以创建一个。)
如果您是 Perl 新手,最好输入use diagnostics;
。无论它认为什么是错误的,你都会得到一个很好的解释。以上是关于Perl 哈希值的基本原理的主要内容,如果未能解决你的问题,请参考以下文章
哈希(Hash)与加密(Encrypt)的基本原理区别及工程应用
算法二分法 ① ( 二分法基本原理简介 | 二分法与哈希表对比 | 常见算法对应的时间复杂度 )