为什么有些用户在 Perl 中引用类名?
Why do some users quote classnames in Perl?
查看Type::Tiny
,我看到官方文档中引用了Type::Tiny->new
调用中的class名称,
my $NUM = "Type::Tiny"->new(
name => "Number",
constraint => sub { looks_like_number($_) },
message => sub { "$_ ain't a number" },
);
这是为什么?这仅仅是风格吗?这种做法对性能有影响吗?
举个更简单的例子
package Foo { sub new { die 7 } };
package Bar { sub new { die 42 } };
sub Foo { "Bar" }
Foo->new();
在上面的示例中,常量 Foo
解析为“Bar”,因此调用 "Bar"->new
而不是 "Foo"->new
。你如何阻止子程序解析?可以引用一下。
"Foo"->new();
至于性能影响,使用字符串而不是裸字不会使情况变得更糟。我已经确认 O=Deparse
生成的 optree 是相同的。所以作为一般规则,如果您重视正确性,似乎最好引用类名。
这在 Programming Perl 中提到,(不幸的是在 间接方法调用 的上下文中)
... so we'll tell you that you can almost always get away with a bare class name, provided two things are true. First, there is no subroutine of the same name as the class. (If you follow the convention that subroutine names like new
start lowercase and class names like ElvenRing
start uppercase, this is never a problem). Second, the class been loaded with one of
use ElvenRing;
require ElvenRing;
Either of these declarations ensures that Perl knows ElvenRing
is a module name, which forces any bare name like new
before the class name ElvenRing
to be interpreted as a method call, even if you happen to have declare a new
subroutine of your own in the current package.
而且,这是有道理的:只有当您的子例程(通常是小写字母)与 class(通常是大写字母)具有相同的名称时,才会发生这里的混淆。这只有在您违反上述命名约定时才会发生。
tldr;引用您的 class 名字可能是个好主意,如果您知道它们并且您重视正确性而不是混乱。
旁注:或者,您可以通过在函数末尾附加 ::
来停止将裸词解析为函数,例如上面的 Foo::->new
.
感谢Ginnz on reddit for pointing this out to me, and to Toby Inkster for the comment (though it didn't make sense to me on first read).
明确引用 class 名称而不是使用裸词(被视为字符串)是避免句法歧义的三种方法之一。 Invoking Class Methods section of the perlobj documentation 说明。
Because Perl allows you to use barewords for package names and
subroutine names, it sometimes interprets a bareword’s meaning
incorrectly. For example, the construct Class->new()
can be
interpreted as either 'Class'->new()
or Class()->new()
.In English,
that second interpretation reads as “call a subroutine named Class()
,
then call new()
as a method on the return value of Class()
.” If there
is a subroutine named Class()
in the current namespace, Perl will
always interpret Class->new()
as the second alternative: a call to
new()
on the object returned by a call to Class()
.
通过下面的演示查看这个奇怪的案例。
#! /usr/bin/env perl
use strict;
use warnings;
sub Type::Tiny { print "Returning Bogus\n" ; return "Bogus" }
sub Type::Tiny::new { print "Type::Tiny::new\n" }
sub Bogus::new { print "Bogus::new\n" }
my $class = "Type::Tiny";
Type::Tiny->new;
Type::Tiny::->new;
"Type::Tiny"->new;
$class->new;
它的输出是
Returning Bogus
Bogus::new
Type::Tiny::new
Type::Tiny::new
Type::Tiny::new
上述文档部分的其余部分展示了如何防止意外行为或意外错误。
You can force Perl to use the first interpretation (i.e., as a
method call on the class named "Class"
) in two ways. First, you can
append a ::
to the class name:
Class::->new()
Perl will always interpret this as a method call.
Alternatively, you can quote the class name:
'Class'->new()
Of course, if the class name is in a scalar Perl will do the right
thing as well:
my $class = 'Class';
$class->new();
针对您的问题,以下所有调用都是等效的。
Type::Tiny::->new( … );
"Type::Tiny"->new( … );
my $class = "Type::Tiny";
$class->new( … );
将 ::
附加到末尾具有产生有用警告的优点。假设您不小心输入了
Type::Tinny::->new;
产生
Bareword "Type::Tinny::" refers to nonexistent package at ./try line 15.
Can't locate object method "new" via package "Type::Tinny" (perhaps you forgot to load "Type::Tinny"?) at ./try line 15.
查看Type::Tiny
,我看到官方文档中引用了Type::Tiny->new
调用中的class名称,
my $NUM = "Type::Tiny"->new(
name => "Number",
constraint => sub { looks_like_number($_) },
message => sub { "$_ ain't a number" },
);
这是为什么?这仅仅是风格吗?这种做法对性能有影响吗?
举个更简单的例子
package Foo { sub new { die 7 } };
package Bar { sub new { die 42 } };
sub Foo { "Bar" }
Foo->new();
在上面的示例中,常量 Foo
解析为“Bar”,因此调用 "Bar"->new
而不是 "Foo"->new
。你如何阻止子程序解析?可以引用一下。
"Foo"->new();
至于性能影响,使用字符串而不是裸字不会使情况变得更糟。我已经确认 O=Deparse
生成的 optree 是相同的。所以作为一般规则,如果您重视正确性,似乎最好引用类名。
这在 Programming Perl 中提到,(不幸的是在 间接方法调用 的上下文中)
... so we'll tell you that you can almost always get away with a bare class name, provided two things are true. First, there is no subroutine of the same name as the class. (If you follow the convention that subroutine names like
new
start lowercase and class names likeElvenRing
start uppercase, this is never a problem). Second, the class been loaded with one ofuse ElvenRing; require ElvenRing;
Either of these declarations ensures that Perl knows
ElvenRing
is a module name, which forces any bare name likenew
before the class nameElvenRing
to be interpreted as a method call, even if you happen to have declare anew
subroutine of your own in the current package.
而且,这是有道理的:只有当您的子例程(通常是小写字母)与 class(通常是大写字母)具有相同的名称时,才会发生这里的混淆。这只有在您违反上述命名约定时才会发生。
tldr;引用您的 class 名字可能是个好主意,如果您知道它们并且您重视正确性而不是混乱。
旁注:或者,您可以通过在函数末尾附加 ::
来停止将裸词解析为函数,例如上面的 Foo::->new
.
感谢Ginnz on reddit for pointing this out to me, and to Toby Inkster for the comment (though it didn't make sense to me on first read).
明确引用 class 名称而不是使用裸词(被视为字符串)是避免句法歧义的三种方法之一。 Invoking Class Methods section of the perlobj documentation 说明。
Because Perl allows you to use barewords for package names and subroutine names, it sometimes interprets a bareword’s meaning incorrectly. For example, the construct
Class->new()
can be interpreted as either'Class'->new()
orClass()->new()
.In English, that second interpretation reads as “call a subroutine namedClass()
, then callnew()
as a method on the return value ofClass()
.” If there is a subroutine namedClass()
in the current namespace, Perl will always interpretClass->new()
as the second alternative: a call tonew()
on the object returned by a call toClass()
.
通过下面的演示查看这个奇怪的案例。
#! /usr/bin/env perl
use strict;
use warnings;
sub Type::Tiny { print "Returning Bogus\n" ; return "Bogus" }
sub Type::Tiny::new { print "Type::Tiny::new\n" }
sub Bogus::new { print "Bogus::new\n" }
my $class = "Type::Tiny";
Type::Tiny->new;
Type::Tiny::->new;
"Type::Tiny"->new;
$class->new;
它的输出是
Returning Bogus Bogus::new Type::Tiny::new Type::Tiny::new Type::Tiny::new
上述文档部分的其余部分展示了如何防止意外行为或意外错误。
You can force Perl to use the first interpretation (i.e., as a method call on the class named
"Class"
) in two ways. First, you can append a::
to the class name:Class::->new()
Perl will always interpret this as a method call.
Alternatively, you can quote the class name:
'Class'->new()
Of course, if the class name is in a scalar Perl will do the right thing as well:
my $class = 'Class'; $class->new();
针对您的问题,以下所有调用都是等效的。
Type::Tiny::->new( … );
"Type::Tiny"->new( … );
my $class = "Type::Tiny";
$class->new( … );
将 ::
附加到末尾具有产生有用警告的优点。假设您不小心输入了
Type::Tinny::->new;
产生
Bareword "Type::Tinny::" refers to nonexistent package at ./try line 15. Can't locate object method "new" via package "Type::Tinny" (perhaps you forgot to load "Type::Tinny"?) at ./try line 15.