【发布时间】:2018-09-20 02:55:27
【问题描述】:
我不明白这里发生了什么:
use PAR { file => 'foo.par', fallback => 1 };
我认为这是一个匿名哈希。 use 行中的模块如何使用它?你能解释一下吗?
编辑:我对 PAR 模块不感兴趣。我只是对幕后的工作方式感兴趣。我怎样才能这样配置我的模块?
【问题讨论】:
标签: perl perl-module
我不明白这里发生了什么:
use PAR { file => 'foo.par', fallback => 1 };
我认为这是一个匿名哈希。 use 行中的模块如何使用它?你能解释一下吗?
编辑:我对 PAR 模块不感兴趣。我只是对幕后的工作方式感兴趣。我怎样才能这样配置我的模块?
【问题讨论】:
标签: perl perl-module
更简单地说,这就是有趣的 hashref 语法的作用(使用 perldoc -f use 作为参考):
假设我们有这个基本模块(把它放在你当前目录的Foo.pm):
package Foo;
use Data::Dumper;
sub import
{
print "import was passed these arguments: ". Dumper(\@_);
}
1;
当我们调用perl -I. -wle'use Foo { a => 1, b => 2}' 时,代码Foo->import({a=>1, b=>2}) 被执行。所以这就是我们得到的输出:
import was passed these arguments: $VAR1 = [
'Foo',
{
'a' => 1,
'b' => 2
}
];
基本上,这种语法可以让我们用Exporter 变魔术,但实际上你可以让import() 做任何你喜欢的事情(只要确保大量记录,以免造成混乱!)
【讨论】:
当您use 一个模块时,您可以将参数列表传递给它。在您的示例中(似乎有错字,缺少右引号),传递了一个包含一个元素(哈希引用)的列表。
更笼统地说:
use Module LIST
变成这样:
BEGIN {
require Module;
Module->import( LIST );
}
BEGIN 块确保所有内容都在编译时发生。 require 将模块加载到内存中,如果它还没有的话。然后使用原始use 语句中传递的任何参数(如LIST)调用模块的import() 方法。
为了让您自己的模块使用这种LIST 的参数做某事,您的模块需要定义一个import() 方法。许多模块不这样做。相反,它们从Exporter 类继承import()。详情请见perldoc -f use。
如果您的模块定义了自己的import() 方法,您将需要自己将符号导出到客户端代码中,或者更常见的是使用Exporter 提供的export_to_level() 方法。此方法的第一个参数是一个正整数,指定调用堆栈中要将符号导出到的级别。最常见的值 1 表示将符号导出到当前包 的上一级——即,导出到正在使用您的模块的客户端代码。以下是您的 import() 方法需要执行的操作的概要。
sub import {
my ($class, @args) = @_;
# Do whatever you need to do with the LIST of arguments
# supplied by the client code using your module.
# Let Exporter do its normal work of exporting symbols
# into the client code using your module.
$class->export_to_level(1, @_);
}
【讨论】:
是的,这是一个匿名哈希。它作为参数传递给模块 import 方法。
【讨论】:
PAR 是 CPAN 模块 Perl Archive Toolkit。 hashref 是传递给 PAR 的配置参数。
代码:
use PAR { file => 'foo.par, fallback => 1 };
use Foo::Bar;
表示使用Foo::Bar(如果可用),否则回退到使用存档“foo.par”(可能包含Foo::Bar 的存档版本)。
【讨论】:
直接回答您的问题:PAR 确实this (line 340):
# called on "use PAR"
sub import {
my $class = shift;
[...]
my @args = @_;
[...]
# process args to use PAR 'foo.par', { opts }, ...;
foreach my $par (@args) {
if (ref($par) eq 'HASH') { # <---- This is what handle's your case!
# we have been passed a hash reference
_import_hash_ref($par);
}
elsif ($par =~ /[?*{}\[\]]/) {
# implement globbing for PAR archives
[...]
}
else {
# ordinary string argument => file
[...]
}
}
现在,不幸的是,一旦您深入了解那里的实际情况,您就会意识到您选择了 CPAN 上最复杂的模块之一作为学习示例,所以我建议您看看fine documentation on modules instead。为您提供一个指导:当您“使用”一个模块并为 use 语句提供参数时,perl 将加载该模块并使用参数列表调用其“import”方法。
在您的示例中,只有一个参数:对哈希的引用。 {key=>"value",key2=>"value2",...} 语法是匿名哈希的构造函数。这些记录在the perlref manual page 中,但在the perlreftut tutorial 中以更友好的方式解释。
【讨论】: