有没有办法让 $a 和 $b 这样的变量严格遵守?

发布于 2024-07-06 01:02:16 字数 1856 浏览 6 评论 0原文

根据迈克尔·卡曼的评论,我决定重写这个问题。 请注意,在此编辑之前出现了 11 条评论,这证实了迈克尔的观察,即我写问题的方式没有明确我要问的内容。


Question: What is the standard--or cleanest way--to fake the special status that $a and $b have in regard to strict by simply importing a module?

首先进行一些设置。 以下内容有效:

#!/bin/perl
use strict;
print "\$a=$a\n";
print "\$b=$b\n";

如果我再添加一行:

print "\$c=$c\n";

我在编译时收到错误,这意味着我的令人眼花缭乱的打印代码都无法运行。

如果我注释掉 use strict; 它运行正常。 除了限制之外,$a$b 主要特殊之处在于 sort 传递要与这些名称进行比较的两个值。

my @reverse_order = sort { $b <=> $a } @unsorted;

因此,$a$b 的主要功能区别——即使 Perl“知道它们的名字”——是你最好排序时要知道这一点,或者使用 List::Util 中的一些函数。

只有当您使用 strict 时,$a$b 才会以全新的方式成为特殊变量。 它们是 strict 唯一会传递而不会抱怨未声明的变量。

现在,我喜欢严格,但让我印象深刻的是,如果 TIMTOWTDI(有不止一种方法可以做到这一点)是 Perl 中的规则 #1,那么这不是很 TIMTOWDI。 它说 $a$b 是特殊的,仅此而已。 如果你想使用变量,你不必声明 $a$b 是你的人。 如果您想通过添加 $c 来获得三个变量,突然间就有了另一种方法可以做到这一点。

没关系,在操作哈希时 $k$v 可能更有意义:

my %starts_upper_1_to_25 
    = skim { $k =~ m/^\p{IsUpper}/ && ( 1 <= $v && $v <= 25 ) } %my_hash
;`

现在,我使用并且喜欢 strict。 但我只是希望 $k$vskim 可见,以获得最紧凑的语法。 我希望它是可见的,只是因为

use Hash::Helper qw<skim>;

我问这个问题不是为了知道如何对它进行黑魔法。 我下面的“回答”应该让你知道我对 Perl 的了解足够多了,这很危险。 我问是否有一种方法可以严格接受其他变量,或者什么是最干净的解决方案。 答案很可能是否定的。 如果真是这样的话,那简直就显得不太TIMTOWTDI了。

In light of Michael Carman's comment, I have decided to rewrite the question. Note that 11 comments appear before this edit, and give credence to Michael's observation that I did not write the question in a way that made it clear what I was asking.


Question: What is the standard--or cleanest way--to fake the special status that $a and $b have in regard to strict by simply importing a module?

First of all some setup. The following works:

#!/bin/perl
use strict;
print "\$a=$a\n";
print "\$b=$b\n";

If I add one more line:

print "\$c=$c\n";

I get an error at compile time, which means that none of my dazzling print code gets to run.

If I comment out use strict; it runs fine. Outside of strictures, $a and $b are mainly special in that sort passes the two values to be compared with those names.

my @reverse_order = sort { $b <=> $a } @unsorted;

Thus the main functional difference about $a and $b--even though Perl "knows their names"--is that you'd better know this when you sort, or use some of the functions in List::Util.

It's only when you use strict, that $a and $b become special variables in a whole new way. They are the only variables that strict will pass over without complaining that they are not declared.

: Now, I like strict, but it strikes me that if TIMTOWTDI (There is more than one way to do it) is Rule #1 in Perl, this is not very TIMTOWDI. It says that $a and $b are special and that's it. If you want to use variables you don't have to declare $a and $b are your guys. If you want to have three variables by adding $c, suddenly there's a whole other way to do it.

Nevermind that in manipulating hashes $k and $v might make more sense:

my %starts_upper_1_to_25 
    = skim { $k =~ m/^\p{IsUpper}/ && ( 1 <= $v && $v <= 25 ) } %my_hash
;`

Now, I use and I like strict. But I just want $k and $v to be visible to skim for the most compact syntax. And I'd like it to be visible simply by

use Hash::Helper qw<skim>;

I'm not asking this question to know how to black-magic it. My "answer" below, should let you know that I know enough Perl to be dangerous. I'm asking if there is a way to make strict accept other variables, or what is the cleanest solution. The answer could well be no. If that's the case, it simply does not seem very TIMTOWTDI.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

小帐篷 2024-07-13 01:02:16

如果我理解你的问题,你想编写一个模块,在用户的命名空间中声明变量(这样他们就不必这样做),并在回调中自动本地化。 是对的吗?

您可以通过声明全局变量并导出它们来做到这一点。 (但请注意,未经要求而导出内容通常被认为是不好的形式。)

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->();
    }
}

注意:导出为 *k*v,而不是 $k$v。 如果您不导出整个 typeglob,则 hashmap 中的 local 将无法在用户包中正常工作。 这样做的副作用是所有各种形式的kv%k>@v 等)得到声明​​和别名。 有关此内容的完整说明,请参阅 perlmod 中的符号表

然后在你的脚本中:

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

If I'm understanding your question you want to write a module that declares variables in the user's namespace (so they don't have to) and which get localized automatically in callbacks. Is that right?

You can do this by declaring globals and exporting them. (Though do note that it's generally considered bad form to export things without being asked to.)

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->();
    }
}

Note: The export is of *k and *v, not $k and $v. If you don't export the entire typeglob the local in hashmap won't work correctly from the user's package. A side effect of this is that all of the various forms of k and v (%k, @v, etc.) get declared and aliased. For a full explanation of this, see Symbol Tables in perlmod.

Then in your script:

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
つ可否回来 2024-07-13 01:02:16

编辑 - 这实际上是不正确,请参阅评论。 把它留在这里是为了让其他人有机会从我的错误中吸取教训:)


哦,你是在问模块是否有办法在 CALLER 的命名空间中声明 $k 和 $v ? 您可以使用 Exporter 将变量推送给调用者:

use strict;

package Test; 
use Exporter;

my @ISA = qw/Exporter/; 
my $c = 3; 
my @EXPORT = qw/$c/; 

package main; 
print $c;

EDIT - this is actually incorrect, see the comments. Leaving it here to give other people a chance to learn from my mistake :)


Oh, you're asking if there's a way for a module to declare $k and $v in the CALLER's namespace? You can use Exporter to push up your variables to the caller:

use strict;

package Test; 
use Exporter;

my @ISA = qw/Exporter/; 
my $c = 3; 
my @EXPORT = qw/$c/; 

package main; 
print $c;
看透却不说透 2024-07-13 01:02:16

建议使用导出的模块实际上与use vars没有什么不同。
但是 use vars 需要在每个使用类似 $a 变量的包中完成。
并且 our() 需要在每个外部作用域中完成。

请注意,您甚至可以通过使用 $$ 原型子程序来避免使用 $a 和 $b 进行排序:

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/;

当在与排序调用不同的包中使用比较例程时,这一点至关重要。

The modules suggested that use export are really no different from use vars.
But the use vars would need to be done in each package that used the $a-like variable.
And our() would need to be done in each outer scope.

Note that you can avoid using $a and $b even for sort by using a $$-prototyped sub:

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/;

This is essential when using a compare routine in a different package than the sort call.

时光匆匆的小流年 2024-07-13 01:02:16

这就是你的追求吗?......

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

Is this what your after?.....

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
千纸鹤带着心事 2024-07-13 01:02:16

我不确定是否有人澄清了这一点,但 strict 不会将 $a 和 $b 列入白名单,只是因为它们确实是方便您在自己的例程中使用的变量名称。 $a 和 $b 对于排序运算符具有特殊含义。 从这样的排序例程的角度来看,这是很好的,但从外部来看,这是一种糟糕的设计。 :) 如果需要的话,您不应该在其他上下文中使用 $a 和 $b 。

I'm not sure if anyone's clarified this, but strict does not whitelist $a and $b just because they are really convenient variable names for you to use in your own routines. $a and $b have special meaning for the sort operator. This is good from the point of view within such a sort routine, but kind of bad design from outside. :) You shouldn't be using $a and $b in other contexts, if you are.

三岁铭 2024-07-13 01:02:16

不过,$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

$a 和 $b 仅存在于传递给 sort() 的块中,之后不存在,并且具有范围,使得任何进一步的 sort 调用都不会继续他们。

为了复制这一点,您可能需要开始搞乱源过滤器,将您喜欢的符号

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
;

$a 和 $b 与 $_ 和 @_ 一样特殊,尽管在 Perl 5 中没有简单的方法来更改这些名称,Perl 6 确实使用给定的关键字修复了这个问题。 “given”是一个搜索垃圾术语,但是 http:// dev.perl.org/perl6/doc/design/syn/S03.html 可能是一个不错的起点。

$a and $b aren't normal variables, though, and can't be easily replicated by either lexical declarations or explicit exports or messing about with the symbol table. For instance, using the debugger as a 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

$a and $b only exist within the block passed to sort(), don't exist afterwards, and have scope in such a way that any further calls to sort don't tread on them.

To replicate that, you probably need to start messing about with source filters, to turn your preferred notation

my %starts_upper_1_to_25 
    = skim { $k =~ m/^\p{IsUpper}/ && ( 1 <= $v && $v <= 25 ) } %my_hash
;

into effectively

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
;

$a and $b are as special as $_ and @_, and while there's no easy way to change those names in Perl 5, Perl 6 does indeed fix this, with the given keyword. "given" is a rubbish term to search on, but http://dev.perl.org/perl6/doc/design/syn/S03.html may be a good place to start.

谁与争疯 2024-07-13 01:02:16

这对我有用:

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;
 } 

它也通过严格传递 $c 。

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”将模块括起来,这有点愚蠢,但我不知道内部结构,这解决了潜在的排序问题。

This worked for me:

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;
 } 

And it passes $c through strict, too.

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";

Yeah, it's kind of dumb that I bracketed my modules with "use strict", but I don't know the internals, and that takes care of potential sequencing issues.

鲸落 2024-07-13 01:02:16

听起来你想做那种魔法 List::MoreUtils 的作用:

use strict;
my @a = (1, 2);
my @b = (3, 4);
my @x = pairwise { $a + $b } @a, @b;

我建议只查看 pairwiseList::MoreUtils中。 它使用一些巧妙的符号表调整将 $a$b 注入调用者的命名空间,然后将它们本地化到子主体内。 我认为。

It sounds like you want to do the sort of magic that List::MoreUtils does:

use strict;
my @a = (1, 2);
my @b = (3, 4);
my @x = pairwise { $a + $b } @a, @b;

I'd suggest just looking at the pairwise sub in the List::MoreUtils source. It uses some clever symbol table fiddling to inject $a and $b into the caller's namespace and then localize them to just within the sub body. I think.

不喜欢何必死缠烂打 2024-07-13 01:02:16

$a$b 只是全局变量。 您可以通过简单地声明 $k$v 来实现类似的效果:(

use strict;
our ($k, $v);

在本例中 $k$v 不是全局变量,而是包变量的词法作用域别名,但如果不跨越边界,它也足够了。)

$a and $b are just global variables. You can achieve similar effects by simply declaring $k and $v:

use strict;
our ($k, $v);

(In this case $k and $v are not global variables, but lexically scoped aliases for package variables. But if you don't cross the boundaries it's similarly enough.)

谁的新欢旧爱 2024-07-13 01:02:16

在 Perl 5.6 及更高版本中,您可以使用我们的:

our ($k, $v);

或者您可以坚持使用旧的“use vars”:

use vars qw($k $v);

或者您可能只坚持使用“my”,例如:

my %hash;
my ($k,$v);
while (<>) {
  /^KEY=(.*)/ and $k = $1 and next;
  /^VALUE=(.*)/ and $v = $1;
  $hash{$k} = $v;
  print "$k $v\n";
}

__END__
KEY=a
VALUE=1
KEY=b
VALUE=2

在上面的示例中,创建全局 $v 并不是真正必要的,但是希望您明白了(另一方面 $k 需要将范围限制在 while 块之外)。

或者,您可以使用完全限定的变量名称:

$main::k="foo";
$main::v="bar";
%main::hash{$k}=$v;

In Perl 5.6 and later, you can use our:

our ($k, $v);

Or you can stick with the older "use vars":

use vars qw($k $v);

Or you might just stick with "my", e.g.:

my %hash;
my ($k,$v);
while (<>) {
  /^KEY=(.*)/ and $k = $1 and next;
  /^VALUE=(.*)/ and $v = $1;
  $hash{$k} = $v;
  print "$k $v\n";
}

__END__
KEY=a
VALUE=1
KEY=b
VALUE=2

Making a global $v is not really necessary in the example above, but hopefully you get the idea ($k on the other hand needs to be scoped outside the while block).

Alternatively, you can use fully qualified variable names:

$main::k="foo";
$main::v="bar";
%main::hash{$k}=$v;
聚集的泪 2024-07-13 01:02:16

如果我理解正确,您想要的是:

use vars qw($a $b); # Pre-5.6

或者

our ($a, $b); # 5.6 +

您可以在此处阅读相关内容。

If I understand correctly, what you want is:

use vars qw($a $b); # Pre-5.6

or

our ($a, $b); # 5.6 +

You can read about it here.

梨涡 2024-07-13 01:02:16

$a 和 $b 很特殊,因为它们是核心语言的一部分。 虽然我可以理解为什么您可能会说无法创建自己的类似特殊变量是反TIMTOWTDI的,但我想说这只不过是无法按“打印”或“的顺序创建新的基本命令”种类'。 (您可以在模块中定义 subs,但这并不会使它们成为真正的关键字。这相当于使用“我们的 $k”,您似乎在说这并不能像 $a 那样使 $k 足够适合您。

)将名称推送到其他人的命名空间中,这应该是 Exporter 的一个工作示例:

package SpecialK;

use strict;

use base 'Exporter';
BEGIN {
  our @EXPORT = qw( $k );
}

our $k;

1;

将其保存到 SpecialK.pm,然后“使用 SpecialK”应该使 $k 可供您使用。 请注意,只能导出“our”变量,而不能导出“my”。

$a and $b are special because they're a part of the core language. While I can see why you might say that the inability to create similarly-special variables of your own is anti-TIMTOWTDI, I would say that it's no more so than the inability to create new basic commands on the order of 'print' or 'sort'. (You can define subs in modules, but that doesn't make them true keywords. It's the equivalent of using 'our $k', which you seem to be saying doesn't make $k enough like $a for you.)

For pushing names into someone else's namespace, this should be a working example of Exporter:

package SpecialK;

use strict;

use base 'Exporter';
BEGIN {
  our @EXPORT = qw( $k );
}

our $k;

1;

Save this to SpecialK.pm and 'use SpecialK' should then make $k available to you. Note that only 'our' variables can be exported, not 'my'.

枕头说它不想醒 2024-07-13 01:02:16

其他人提到如何“使用变量”和“我们的” - 我只是想补充一点,$a 和 $b 是特殊情况,因为它们由排序例程内部使用。 以下是 strict.pm 文档中的注释:

Because of their special use by sort(), the variables $a and $b are 
exempted from this check.

Others mentioned how to 'use vars' and 'our' - I just wanted to add that $a and $b are special cases, since they're used internally by the sort routines. Here's the note from the strict.pm docs:

Because of their special use by sort(), the variables $a and $b are 
exempted from this check.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文