语法是将多个值的修改封装在一个语句中的一种不同寻常的方式。
此代码可能在子程序的末尾使用,因为它返回一个值列表。真正的代码可能是这样的。
sub foo {
my @a = qw(Sun Mon Tue Wed Thu Fri Sat);
my @b = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
my $s = q{foobar};
# wday month mday hour min sec year
return sub { ( $a[ $_[6] ], $b[ $_[4] ], $_[3], $_[2], $_[1], $_[0], $_[5] + 1900 ) }
->(localtime), $s;
}
让我们来看看。我添加了return 以更清楚地了解正在发生的事情。
有一个匿名子程序sub { ... },它被定义并直接被称为sub { ... }->()。这就像一个 lambda 函数。这种形式的箭头运算符-> 用于调用代码引用。它与直接对象语法(例如$foo->frobnicate())的不同之处在于箭头后面没有方法名称。
my $code = sub { print "@_" };
$code->(1, 2, 3);
这将输出:
1, 2, 3
传递了列表上下文中的localtime 返回值。这是当前时间的一堆值,如 in the documentation 所述。
# 0 1 2 3 4 5 6 7 8
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
localtime(time);
没有参数,localtime 隐式使用 time 作为其参数。在匿名子例程内部,这些值以@_ 结尾,这是子程序的参数列表。所以$_[0] 是当前本地日期的秒部分。
然后是@a 和@b,它们的名字选择得非常糟糕。如果它应该是短的,我至少会在工作日和几个月里给他们打电话 @d 和 @m。
匿名子返回一个值列表。这是当前工作日,在 @a 数组中查找,其中星期日是索引 0,在 @b 中查找的当前月份,日、时、分和秒,以及四位数的年份编号(因此是+ 1900)。
整个函数foo返回这个列表,另一个值$s作为其返回值列表的最后一个元素。
如果你要print所有这些,你会得到:
print join q{ }, foo();
__END__
Mon Sep 25 16 10 33 2017 foobar
在sprintf 的上下文中,这一点变得更加清晰。可能是为日志条目添加时间戳。
sub log {
my $s = shift;
my @a = qw(Sun Mon Tue Wed Thu Fri Sat);
my @b = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
# 0 1 2 3 4 5 6 7
$s = sprintf "%s %s %d %d:%d:%d %d: %s",
# wday month mday hour min sec year
# 0 1 2 3 4 5 6
sub { ( $a[ $_[6] ], $b[ $_[4] ], $_[3], $_[2], $_[1], $_[0], $_[5] + 1900 ) }
# 7
->(localtime), $s;
return $s;
}
print &log('stuff happened'); # we need the & because CORE::log
我已经用sprintf 模式内的参数位置标记了每个值。 $s 似乎是日志消息,它被替换为带有时间戳的新字符串,并将其本身作为最后一个参数。
但是,这是一个非常不寻常的实现,因为 localtime 将在标量上下文中返回完全相同的内容。
print &log("stuff happened\n");
print ''.localtime . ": stuff happened\n";
__END__
Mon Sep 25 16:24:40 2017: stuff happened
Mon Sep 25 16:24:40 2017: stuff happened
ctime(3)的返回值。我首先认为这可能是重新实现,因为在目标系统上不存在这种时间戳,但localtime 文档也说这与系统无关。
此标量值的格式不依赖于语言环境,而是内置于
珀尔。对于 GMT 而不是本地时间,请使用 gmtime 内置。也可以看看
Time::Local 模块(用于转换秒、分、小时和
这样回到时间返回的整数值),以及 POSIX
模块的 strftime 和 mktime 函数。
sub 的实现很优雅,虽然不是 Perl 风格。但是,它完全没用,因为 Perl 已经提供了完全相同的格式。
你可以很容易地用这个替换我的log函数。
sub log {
my $s = shift;
$s = localtime . " $s";
return $s;
}
但话又说回来,如果 @a 和 @b 可能是本地化的,这是有道理的。您将它们作为字母提供,这可能不是您的真实代码,但我可以看到这被用作例如将其翻译成这样的德语。
use utf8;
sub log {
my $s = shift;
my @a = qw(So Mo Di Mi Do Fr Sa);
my @b = qw(Jan Feb Mär Apr Mai Jun Jul Aug Sep Okt Nov Dez);
# 0 1 2 3 4 5 6 7
$s = sprintf "%s %s %d %d:%d:%d %d: %s",
# wday month mday hour min sec year
# 0 1 2 3 4 5 6
sub { ( $a[ $_[6] ], $b[ $_[4] ], $_[3], $_[2], $_[1], $_[0], $_[5] + 1900 ) }
# 7
->(localtime), $s;
return $s;
}
print &log("stuff happened\n");
现在更有意义了。