夜雨聆风学习资料网

ARTICLE · 988403

Excel VBA 编程 -- 作用域(二)

Excel VBA 编程 -- 作用域(二)
前面我们简单介绍了一下 VBA 中程序对象的作用域,主要讨论了变量(含常量)的三种作用域:本地过程级(procedure-level),模块级(private module-level),项目级(public module-level)。
项目级作用域,也称为模块级公有作用域,是指作用范围遍及整个 VBA 项目,包括当前项目中的各个模块,以及各个加载项。
下面来看一个访问加载项中公有变量的例子。
例1. 访问加载项中的变量
图1 加载项 PiVBALibProject
在加载项 PiVBALibProject 中,我们声明了一个公有变量 gName。这个变量可以在引入该加载项的项目中访问,如下图:
图2 访问加载项中的变量
当前项目是 ExcelVBAScope,引用了加载项 PiVBALibProject,因此就可以访问 PiVBALibProject 中的公有变量 gName。
如图1 所示,我们在加载项中声明了两个变量:一个是公有变量 gName,一个是私有变量 epsilon。gName 可以在当前项目中访问,已如上述。但私有变量则不能在当前项目中访问,如下图所示:
图3 访问加载项中的私有变量
如图所示,epsilon 变量的作用域是声明该变量的模块,即 PiVBALibProject 中的模块 pModule,外部模块不得访问。因为在当前项目的当前模块中没有声明 epsilon,所以引发“变量未定义”错误。
由这个例子也可以看出,gName 声明为 Public,则 gName 不仅可以被PiVBALibProject 项目的所有模块访问,还可以被引用该项目的各模块访问。因此,VBA 的项目级变量是一种全局变量。
由此可见,VBA 对变量作用域的划分是相对简单和粗粒度的:
  • 没有如 C 语言中的块级(block)设施,一个变量用 Dim 声明为过程级,则整个过程都可见。
  • 没有如 C# 语言中的程序集(assembly)设施,所以,没有办法声明只用于项目内部的变量,譬如声明只能在 PiVBALibProject 内部各模块之间公有的变量。像 gName 那样声明为 Public,则既能在 PiVBALibProject 项目各模块之间共享,也能在项目 ExcelVBAScope 中共享,只要在 ExcelVBAScope 项目中加载 PiVBALibProject 即可。
基于此,在 VBA 代码中,尽量使用本地过程级变量,谨慎使用模块级变量,控制使用(尽量不使用)项目级变量。
变量的可见性
前文说过,与作用域概念相关的还有可见性(Visibility)和可访问性(Accessibility),而且一般来说,在 VBA 中,这三个概念所表述的变量范围基本上是一致的。
但也有不一致的时候,见下例。
例2. 作用域与可见性不一致
图4 变量的作用域与可见性不一致
在这个例子中,首先声明了一个模块级私有变量 Name,也就是说,Name 变量的作用域是整个的当前模块。
然后,在过程 Sc3Test2 中,又声明了一个过程级的变量 Name,此时,该过程级的本地变量 Name 就“遮盖”了比它高一级的模块私有变量 Name。这就是说,虽然模块级 Name 的作用域包括了过程 Sc3Test2,但因为过程级 Name 的遮盖,模块级 Name 变得“不可见”。
再看下例。
例3. 作用域与可见性不一致
图5 作用域与可见性不一致
这个例子,Sc3Test2 过程仍然遮蔽了模块级变量 Name。在过程末尾,调用了另一个过程 Sc3Test3。而在 Sc3Test3 中,没有过程级的变量与模块级变量同名,因此,在 Sc3Test3 过程内,模块级的变量 Name 是可见的。从输出结果可见:第一行 Debug.Print 输出空白,因为此时 Name 变量没有值。接下来对 Name 赋值,因此第二行的 Debug.Print,模块级变量 Name 的值就打印出来了。
由此例可见,因为级别低的变量(即作用域小的变量)会“遮蔽”级别高(即作用域大)的同名变量,因此,在程序开发时要特别注意这一点,也许这就是程序错误的源头。
基于此,各个级别的变量命名最好遵循一定的规则,譬如:全局变量以 g_ 开头,模块级变量以 m_ 或 mk_ 开头。如此可最大程度上避免名字被遮蔽导致的错误。
相关阅读
Excel VBA 编程 -- 作用域(一)

相关学习资料