Perl 是否有某种方法可以使变量像$a和$b这样严格地符合要求?
根据迈克尔·卡曼的评论,我决定重写这个问题。请注意,在本次编辑之前出现了11条评论,并证实了Michael的观察,即我在撰写问题时没有明确说明我的问题。Perl 是否有某种方法可以使变量像$a和$b这样严格地符合要求?,perl,timtowtdi,Perl,Timtowtdi,根据迈克尔·卡曼的评论,我决定重写这个问题。请注意,在本次编辑之前出现了11条评论,并证实了Michael的观察,即我在撰写问题时没有明确说明我的问题。 问:$a和$b通过简单地导入一个模块来伪造严格限制方面的特殊状态的标准或最干净的方法是什么 首先是一些设置。以下工作: #!/bin/perl use strict; print "\$a=$a\n"; print "\$b=$b\n"; 如果我再添加一行: print "\$c=$c\n"; 我在编译时遇到了一个错误,这意味着我的所有令
问:
$a
和$b
通过简单地导入一个模块来伪造严格限制方面的特殊状态的标准或最干净的方法是什么
首先是一些设置。以下工作:
#!/bin/perl
use strict;
print "\$a=$a\n";
print "\$b=$b\n";
如果我再添加一行:
print "\$c=$c\n";
我在编译时遇到了一个错误,这意味着我的所有令人眼花缭乱的打印代码都无法运行
如果我注释掉使用strict代码>运行良好。除了限制之外,$a
和$b
主要的特殊之处在于排序
传递两个值以与这些名称进行比较
my @reverse_order = sort { $b <=> $a } @unsorted;
现在,我使用和我喜欢严格。但是我只希望$k
和$v
对skim
可见,以获得最简洁的语法。我希望它能被人看到
use Hash::Helper qw<skim>;
使用Hash::Helper qw;
我问这个问题并不是为了知道如何使用黑魔法。我下面的“答案”应该让您知道,我知道的Perl足够危险。我想问的是,是否有一种方法可以让严格接受其他变量,或者什么是最干净的解决方案。答案很可能是否定的。如果是这样的话,那就不太可能了 $a
和$b
只是全局变量。只需声明$k
和$v
即可实现类似效果:
use strict;
our ($k, $v);
(在本例中,$k
和$v
不是全局变量,而是包变量的词汇范围别名。但如果不跨越边界,这就足够了。)如果我理解正确,您需要的是:
use vars qw($a $b); # Pre-5.6
或
您可以阅读。其他人提到了如何“使用变量”和“我们的”-我只想补充说$a和$b是特殊情况,因为它们在内部由排序例程使用。以下是strict.pm文档中的注释:
Because of their special use by sort(), the variables $a and $b are
exempted from this check.
在Perl 5.6及更高版本中,您可以使用我们的:
our ($k, $v);
或者,您可以坚持使用较旧的“使用变量”:
或者您可能只使用“我的”,例如:
编辑-这实际上是不正确的,请参见注释。把它留在这里是为了给别人一个从我的错误中吸取教训的机会:)
哦,您在问模块是否有方法在调用方的命名空间中声明$k和$v?您可以使用Exporter向调用者推送变量:
use strict;
package Test;
use Exporter;
my @ISA = qw/Exporter/;
my $c = 3;
my @EXPORT = qw/$c/;
package main;
print $c;
$a和$b是特殊的,因为它们是核心语言的一部分。虽然我能理解为什么你可能会说,不能创建自己的类似特殊变量是反TIMTOWTDI的,但我想说的是,不能按照“打印”或“排序”的顺序创建新的基本命令。(您可以在模块中定义sub,但这并不能使它们成为真正的关键字。这相当于使用“我们的$k”,您似乎在说它不能使$k足够像$a。)
要将名称推入其他人的命名空间,这应该是Exporter的一个工作示例:
package SpecialK;
use strict;
use base 'Exporter';
BEGIN {
our @EXPORT = qw( $k );
}
our $k;
1;
将此保存到SpecialK.pm,然后“使用SpecialK”将为您提供$k。请注意,只能导出“我们的”变量,而不能导出“我的”。听起来您想做一种神奇的事情:
我建议只看一下成对的sub。它使用一些巧妙的符号表来将$a
和$b
注入调用方的名称空间,然后将它们定位到子主体中。我想。这对我来说很有效:
package Special;
use base qw<Exporter>;
# use staging; -> commented out, my module for development
our $c;
our @EXPORT = qw<manip_c>;
sub import {
*{caller().'::c'} = *c;
my $import_sub = Exporter->can( 'import' );
goto &$import_sub;
}
是的,我用“use strict”将模块括起来有点愚蠢,但我不知道其内部结构,这就解决了潜在的排序问题 这就是你想要的吗
use strict;
use warnings;
use feature qw/say/;
sub hash_baz (&@) {
my $code = shift;
my $caller = caller;
my %hash = ();
use vars qw($k $v);
no strict 'refs';
local *{ $caller . '::k' } = \my $k;
local *{ $caller . '::v' } = \my $v;
while ( @_ ) {
$k = shift;
$v = shift;
$hash{ $k } = $code->() || $v;
}
return %hash;
}
my %hash = (
blue_cat => 'blue',
purple_dog => 'purple',
ginger_cat => 'ginger',
purple_cat => 'purple' );
my %new_hash = hash_baz { uc $v if $k =~ m/purple/ } %hash;
say "@{[ %new_hash ]}";
# => purple_dog PURPLE ginger_cat ginger purple_cat PURPLE blue_cat blue
我不确定是否有人对此进行了澄清,但strict并没有将$a和$b列为白名单,因为它们确实是方便您在自己的例程中使用的变量名$a和$b对排序运算符有特殊意义。从这样一个排序例程的角度来看,这是好的,但从外部来看,这是一种糟糕的设计。:)如果可以,您不应该在其他上下文中使用$a和$b。如果我理解您的问题,您需要编写一个模块,在用户的名称空间中声明变量(因此它们不必),并在回调中自动本地化。是这样吗
您可以通过声明全局变量并导出它们来实现这一点。(不过请注意,通常认为未经要求就导出内容是不好的。)
注意:导出的是*k
和*v
,而不是$k
和$v
。如果不导出整个typeglob,hashmap
中的local
将无法从用户的包中正常工作。这样做的一个副作用是,所有形式的k
和v
(%k
,@v
等)都被声明并使用别名。有关这方面的完整解释,请参阅
然后在脚本中:
use Foo; # exports $k and $v
my %h = (a => 1, b => 2, c => 3);
hashmap { print "$k => $v\n" } %h;
__END__
c => 3
a => 1
b => 2
虽然$a和$b不是普通变量,也不能通过词法声明或显式导出或与符号表混淆来轻松复制。例如,将调试器用作shell:
DB<1> @foo = sort { $b cmp $a } qw(foo bar baz wibble);
DB<2> x @foo
0 'wibble'
1 'foo'
2 'baz'
3 'bar'
DB<3> x $a
0 undef
DB<4> x $b
0 undef
DB@foo=sort{$bcmp$a}qw(foo-bar-baz-wibble);
DB x@foo
0“wibble”
1‘foo’
2‘baz’
3“酒吧”
DB x$a
0未定义
DB x$b
0未定义
$a和$b只存在于传递给sort()的块中,之后不存在,并且其作用域的方式使对sort的任何进一步调用都不会影响它们
要复制这一点,您可能需要开始混淆源过滤器,以改变您首选的符号
my %starts_upper_1_to_25
= skim { $k =~ m/^\p{IsUpper}/ && ( 1 <= $v && $v <= 25 ) } %my_hash
;
my%从上到下开始
=skim{$k=~m/^\p{IsUpper}/&(1建议使用导出的模块与使用变量的模块实际上没有什么不同。
但是
use strict;
my @a = (1, 2);
my @b = (3, 4);
my @x = pairwise { $a + $b } @a, @b;
package Special;
use base qw<Exporter>;
# use staging; -> commented out, my module for development
our $c;
our @EXPORT = qw<manip_c>;
sub import {
*{caller().'::c'} = *c;
my $import_sub = Exporter->can( 'import' );
goto &$import_sub;
}
package main;
use feature 'say';
use strict;
use Special;
use strict;
say "In main: \$c=$c";
manip_c( 'f', sub {
say "In anon sub: \$c=$c\n"; # In anon sub: $c=f
});
say "In main: \$c=$c";
use strict;
use warnings;
use feature qw/say/;
sub hash_baz (&@) {
my $code = shift;
my $caller = caller;
my %hash = ();
use vars qw($k $v);
no strict 'refs';
local *{ $caller . '::k' } = \my $k;
local *{ $caller . '::v' } = \my $v;
while ( @_ ) {
$k = shift;
$v = shift;
$hash{ $k } = $code->() || $v;
}
return %hash;
}
my %hash = (
blue_cat => 'blue',
purple_dog => 'purple',
ginger_cat => 'ginger',
purple_cat => 'purple' );
my %new_hash = hash_baz { uc $v if $k =~ m/purple/ } %hash;
say "@{[ %new_hash ]}";
# => purple_dog PURPLE ginger_cat ginger purple_cat PURPLE blue_cat blue
package Foo;
use strict;
use warnings;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(*k *v hashmap);
our ($k, $v);
sub hashmap(&\%) {
my $code = shift;
my $hash = shift;
while (local ($k, $v) = each %$hash) {
$code->();
}
}
use Foo; # exports $k and $v
my %h = (a => 1, b => 2, c => 3);
hashmap { print "$k => $v\n" } %h;
__END__
c => 3
a => 1
b => 2
DB<1> @foo = sort { $b cmp $a } qw(foo bar baz wibble);
DB<2> x @foo
0 'wibble'
1 'foo'
2 'baz'
3 'bar'
DB<3> x $a
0 undef
DB<4> x $b
0 undef
my %starts_upper_1_to_25
= skim { $k =~ m/^\p{IsUpper}/ && ( 1 <= $v && $v <= 25 ) } %my_hash
;
my %starts_upper_1_to_25
= map { my $k = $_; my $v = $my_hash{$v};
$k =~ m/^\p{IsUpper}/ && ( 1 <= $v && $v <=> 25 ) } keys %my_hash
;
sub lccmp($$) { lc($_[0]) cmp lc($_[1]) }
print join ' ', sort lccmp
qw/I met this guy and he looked like he might have been a hat-check clerk/;