乐于分享
好东西不私藏

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

Excel VBA 编程 -- 作用域(一)
关于 Excel VBA 编程,还剩最后一个非常重要的题目,那就是作用域。
什么是作用域(scope)?作用域是指一个程序对象(变量、常量、过程)起作用的范围。正如对于一个函数 f(x) 来说,x 要有一定的取值范围一样,在一个 VBA 程序中,程序对象也有一定的作用范围;正如超出 x 的取值范围,函数无意义一样,超出程序对象的作用范围,该程序对象也无意义(VBA 报错:变量未定义)。函数 f(x) 中 x 的取值范围叫做定义域(domain),VBA 中程序对象的作用范围叫做作用域(scope)。
本文先讨论变量(含常量,下同)的作用域,过程的作用域留待下文。
与变量的作用域(scope)相联系的,还有两个概念:一个是可见性(visibility),另一个是可访问性(accessibility)。在 VBA 中,可见性基本上等同于可访问性,这也就是说,只要你能看得见(visible),就能访问(accessible)。
    VBA 变量的作用域有三个层级:
    • 本地(Procedure-level)
      • 是指在过程(Sub/Function)之内用 Dim 声明的变量
    • 模块(Private module-level)
      • 是指在模块声明区域用 Private 声明的变量
      • 在模块声明区域用 Dim 声明的变量默认为 Private 声明
    • 项目(Public module-level)
      • 是指在模块声明区域用 Public 声明的变量
    本地变量(过程级变量)
    在过程(Sub/Function)之内用 Dim 声明的变量,其作用域就限于该过程,在该过程之外,此变量无意义。即使在该过程之外有同名的变量,那也是另外的变量,与此变量无关。
    另外,在过程之内声明变量时,只能使用 Dim 声明语句,不能使用 Private/Public。
    模块级变量
    指在模块声明区域(即模块顶部)用 Private 声明语句声明的变量。在模块声明区域可以使用 Dim 声明语句,但视为 Private。所以在模块声明区域声明模块变量,请使用 Private 语句,Private 比 Dim 能更好地表达程序员的意图,因此有更好的自文档化(self-documentation)作用。
    模块级变量只能在当前模块中可见,因此只能在当前模块中使用。
    VBA 文档将模块级变量称为模块级私有(Private module-level)变量
    项目级变量
    指在模块声明区域用 Public 声明语句声明的变量。用 Public 语句声明的变量在整个 VBA 项目中都可见,因此在整个项目的任何模块中都可以使用。
    VBA 文档将项目级变量称为模块级公有(Public module-level)变量。
    例1. 变量作用域示例
    图1 变量作用域示例
    在这个例子中,先是在模块声明区域声明了两个变量:一个是用 Public 声明的项目级变量 Name,一个是用 Private 声明的模块级变量 Height。
    然后,在过程 WhoIsHelen 中,使用 Dim 语句声明了一个本地(过程级)变量 Age。
    三个不同级别的变量,Age, Height, Name,都可以在当前过程中访问。因为 Name 是项目级变量,因此可以在当前项目的所有模块中访问,如下图所示:
    图2 变量作用域示例-2
    在当前项目的 ScCode2 模块中,可以使用在 ScCode1 模块中声明的项目级(模块公有)变量 Name,如图中代码所示,在过程 NameChanger 中对 Name 重新赋值,然后,在 ScCode1 模块的 WhoIsHelen 过程中,最后访问 Name 时,Name 的值已经是修改过的新值了。
    不同级别的变量,既给我们带来了方便,也带来了危险。如果 ScCode1 模块中的公有变量 Name 不小心被其他模块修改了,在程序运行中就会造成麻烦。所以,尽量使用本地变量,将变量尽可能地控制在过程内部。如果需要在模块内的各个过程之间共享变量,则使用 Private 将变量声明为模块级。如果实在需要在项目的各个模块之间共享变量,再使用 Public 将变量声明为项目级。尽量减少项目级变量的使用。