【问题标题】:When should you use a package variable vs a lexical variable (and what's the difference)?什么时候应该使用包变量和词法变量(有什么区别)?
【发布时间】:2009-06-19 19:17:28
【问题描述】:

我正在查看Perl Monks 上的一些较旧的 Perl 代码,以了解如何使用 Win32::OLE 和 MS Word 进行编程。散布在整个代码中的是名称如 $MS::Word 等的变量,它们的声明中没有包含“my”。在 Google 上阅读了一下之后,我了解到这些被称为“包变量”而不是使用 my 声明的“词法变量”。

我的第一个问题是“包变量有什么用?”。我(认为)我了解词法变量是什么,但我不了解包变量的用途或它们的使用与词法有何不同,所以我的第二个问题是,'词法变量和包变量有什么区别?'

【问题讨论】:

  • 顺便说一句,查看该代码的其他人称其为“丑陋”。我不确定如何判断它是否丑陋。有人愿意开导我吗? :)
  • 在某种程度上它很丑,因为它在做 OLE。那从来都不漂亮。我对代码的主要抱怨是滥用包变量。它广泛使用它们,但从不声明一个包。这表明作者并不真正了解他所使用的工具。
  • OLE 从来都不漂亮,但 Perl 代码不必这么丑。 15 年前我不得不处理一些 Cobol 代码时,我仍然回想起那段时光。

标签: perl variables scope package lexical


【解决方案1】:

您应该阅读 MJD 的 Coping with Scoping

perldoc perlmod 也是有用的阅读材料。

代码太丑陋了。仅仅因为作者似乎认为 $author::email 很酷,它就践踏了各种命名空间。

更好的方法是使用哈希:

my %author = (
   email => 'author@example.com',
   ...
);

没有必要遍历符号表。

我确实有一些Win32::OLE 示例:http://www.unur.com/comp/ 不是艺术品,但我相信这是对这种风格的改进。另见Why are the number of pages in a Word document different in Perl and Word VBA?

我要吐槽一下

@pgm::runtime_args = @ARGV ;

所以,我们放弃标准的@ARGV 数组来践踏pgm 命名空间。不仅如此,每个 Perl 程序员都知道@ARGV 是什么。无论如何,@pgm::runtime_args 不会在脚本中再次使用。

$pgm::maxargs = $#pgm::runtime_args + 1 ;

当然,@pgm::runtime_args 在标量上下文中会给我们该数组中元素的数量。我不知道为什么可能需要$pgm::maxargs,但如果需要,那么这行应该是:

$pgm::maxargs = @pgm::runtime_args;

我不会再引用这些东西了。我想这就是 Cobol 程序员尝试编写 Perl 时会发生的情况。

$program::copyright = "Copyright (c) 02002 - Kenneth Tomiak : All rights reserved.";

我很高兴他为这一年分配了五位数。你永远不知道!

PS:我相信我的摘录构成合理使用。

【讨论】:

  • 啊,但是前面的 0 表示它是一个八进制数 - 显然,版权日期是 1026 年,所以代码现在应该是公共领域的。 :)
【解决方案2】:

一个包变量存在于一个符号表中,所以给定它的名字,就可以从任何其他包或作用域读取或修改它。词法变量的范围由程序文本决定。 perlsub 联机帮助页中的 "Private Variables via my()" 部分提供了有关定义词法的更多详细信息。

假设我们有以下MyModule.pm

package MyModule;

# these are package variables
our $Name;
$MyModule::calls = "I do not think it means what you think it means.";

# this is a lexical variable
my $calls = 0;

sub say_hello {
  ++$calls;

  print "Hello, $Name!\n";
}

sub num_greetings {
  $calls;
}

1;

请注意,它包含一个包$calls 和一个词法$calls。任何人都可以访问前者,但模块控制对后者的访问:

#! /usr/bin/perl

use warnings;
use strict;

use MyModule;

foreach my $name (qw/ Larry Curly Moe Shemp /) {
  $MyModule::Name = $name;
  MyModule::say_hello;
}

print MyModule::num_greetings, "\n";

print "calls = $MyModule::calls\n";

程序的输出是

Hello, Larry!
Hello, Curly!
Hello, Moe!
Hello, Shemp!
4
calls = I do not think it means what you think it means.

如您所见,包变量是全局变量,因此所有常见的陷阱和建议都反对 apply。除非明确提供访问权限,否则 MyModule 包之外的代码不可能访问其词法 $calls

经验法则是你几乎总是想使用词汇。 Damian Conway 的Perl Best Practices 是直接的:“永远不要让变量成为模块接口的一部分”(强调原文)。

【讨论】:

  • +1 并被接受 - 这个答案最能回答我的问题。谢谢!
【解决方案3】:

包变量是全局变量;它们在整个程序(甚至其他模块)中随处可见。当您想要或需要那种级别的可见性和/或外部影响时,它们很有用。例如,Text::Wrap 模块使用它们来允许单个配置点用于换行文本的列数。此外,包变量允许您使用称为“动态范围”的东西——但这是一个有点高级且有点深奥的概念。

关于第二个问题,请参阅What is the difference between my and our in Perl?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-19
    • 2016-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-04
    • 2011-01-14
    相关资源
    最近更新 更多