3.2 变量与常量
如果一个程序中所有的值都是预先设置好的,而不能根据运行时候的变化而变化,那么这样的代码价值就会打很大的折扣。变量能够使得程序变得更加富有活力。
3.2.1 变量名称
变量是指在代码运行过程中其值能够发生变化的量。当程序运行的时候,会在计算机的内存中提供一些区域给变量,这些区域就能放置变量的值。为了在修改和读取内存存储区域的值时不发生错误,需要给内存中这些位置进行命名,以便在一定的范围内具有唯一性。
VBA变量可以使用的名称由不超过255个字节的字母、数字和某些特定的符号组成,并且不区分大小写,但是在实际应用中也要特别注意以下的一些问题。
1. 不使用关键字做变量名
作为变量名称的字母组合不能和VBA中的关键字相同,否则会出现错误。
例3-03:在模块中输入代码,将某个变量名称定义为if,数据类型为整型。
由于If就是VBA中固有的关键字,它不能作为变量的名称。代码输入完成的时候就会出现如图3-3所示的错误提示。
图3-3 变量名称错误
2. 变量名中不能使用某些符号
变量名中也可以包含标点符号,但也不是所有的标点符号都可以出现在变量名称内,对于某些具备特定含义的符号例如(、#、*、%以及!等都不可以出现在变量名称中。通常最多使用的符号是下画线“_”。
3. 大小写混写方式
在VBA中由于变量的名称是不区分大小写的,例如将某个变量定义为“myline”或“myLine”,在实际运行的时候,其执行的效果都是一致的。但是在定义变量名称的时候通常还是会用大小写混写的方式来进行,这样做的目的是为了便于阅读和保证变量书写的正确性。
用户如果在声明的时候将变量声明为大小写混写的方式,那么用户今后在输入该变量的时候,可以用英文状态的小写字母输入。如果输入的变量和声明的变量字母相同(不考虑大小写),那么系统会自动将全部小写输入的字母更改为大小写混合的方式,如果用户输入的变量名称和声明的变量字母不相同,那么系统就不会将其转化为大小写混合的方式。
例3-04:在模块中定义一个test过程,在该过程中声明一个名为“myNewLineNumber”的整型变量,具体输入的代码如下所示,观察将第3行代码中变量名输入为 “mynewlinenumber”就“mynewlinnumber”时,换行后代码发生的变化。
#001: Sub test() #002: Dim myNewLineNumber As Integer #003: myNewLineNumber = 1 #004: End Sub
第2行用户将变量设置为大小写混合的方式,那么在第3行代码中输入“mynewlinenumber”,该行完成后,程序会自动将全部小写字母输入的内容恢复为“myNewLineNumber”。而如果在第3行中,用户将变量输入为“mynewlinnumber”,由于输入错误,那么所有的字母仍旧是小写状态,而不会变成大小写混合的方式。通过这点可以提示用户变量输入是否正确。
4. 使用中文名称
和大多数的编程语言都不同,VBA对变量名称的管理是很宽松的,只要用户愿意甚至可以用中文作为变量。
例3-05:在模块中定义一个名为“中文变量”的过程。在该过程中使用了一个名为“销售数量”的整数变量,并销售数量定义为100,用消息框显示销售数量。
用户可以在模块的代码窗口中输入下述代码。
#001: Sub中文变量() #002: Dim销售数量As Integer #003: 销售数量 = 100 #004: MsgBox销售数量 #005: End Sub
代码输入完成后,单击工具栏上的运行按钮,就能够以一个消息框的方式给出结果。上述代码中,第2行代码就使用“销售数量”作为一个变量的名称。
注意
虽然可以使用中文变量,但是在实际运用中还是很少采用这样的变量表示方式。
3.2.2 变量声明
声明变量的作用就是在计算机内存中划分出一个存储区域来放置指定的变量的值。在一定的范围内,变量的名称是唯一的。
变量的名称表示在计算机的内存中为某个存储区域进行标示。但实际上系统并不知道应该在何时去内存中申请存储区域,这需要用户利用变量声明的过程来告知系统,将要使用计算机的某个存储区域。变量声明的时候指定了存储区域的大小和名称,名称就是上节所说的变量名,而大小则是由数据类型所规定的。
1. 变量声明方式
通常使用Dim来声明变量,其语法格式是:
Dim变量名As数据类型
可以用一行来声明多个变量,变量和变量之间用逗号隔开,其表示方式如下。
Dim a As Integer, b As Double, c As Single
这行代码就声明了三个变量a、b和c,其数据类型分别是Integer、Double和Single。
除了使用Dim声明变量外,还可以使用Private、Static和Public等关键字来声明变量。它们之间的区别在于变量的作用范围不一样。
2. 隐式声明
一般说,变量使用前都需要经过声明,否则内存并不会自动为变量分配存储单元。但实际上,VBA是可以不经过声明就直接使用变量的。这是因为VBA将这些没有声明的变量自动声明为了Variant类型,这种不经过声明就直接使用的变量声明方式就是隐式声明。变量不经声明就直接使用对运行的结果没有影响,但是会对输入过程和运行速度产生一定的影响。
例3-06:在模块中输入以下代码,分别比较声明变量和不声明变量两种方法,在实际输入过程中区别。
#001: Sub不声明变量() #002: ActiveSheet.Range("a1").Value = 1 #003: End Sub #004: #005: Sub声明变量() #006: Dim mySht As Worksheet #007: Set mySht = ActiveSheet #008: mySht.Range("a1").Value = 1 #009: End Sub
虽然上述两段代码的运行结果完全一致,但是在输入的过程中可以发现。输入第2行代码的时候,用户输入完ActiveSheet和点号后,屏幕没有出现任何属性和方法的提示。而在输入“声明变量”过程中的第8行代码的时候,用户输入完ActiveSheet和点号后则会出现属性和方法的提示。
3. 强制声明
变量使用前先声明是一个好的习惯。由于VBA可以隐式声明,因此用户可能会经常忘记这一点,为此可以要求对变量进行强制声明。
对变量强制声明的方法是:在VBE窗口中,打开“工具”菜单,执行“选项”命令,打开如图3-4所示的选项对话框。在“编辑器”选项卡中的“代码设置”选项组中选择“要求变量声明”复选框,单击“确定”按钮,完成变量强制声明的设置。
图3-4 选项对话框
设置了变量强制声明后,就会在模块的最上端出现一行代码“Option Explicit”。此时再输入上述“不声明变量”过程,运行该过程,则会出现如图3-5所示的错误提示,表示要求用户要对所有使用到的变量进行声明。
图3-5 错误提示
3.2.3 变量类型声明字符
为了和以往的BASIC版本相衔接,VBA也可以采用将字符放在变量名称来标示变量类型。用户在阅读以往的程序时候,可能会遇到这种表示方法。
不同的数据类型可以用表3-2所示的字符来表示。下表中已经列示了所有的数据类型的字符表示方式,如果没有列示出来,表示不存在类型声明字符。
表3-2 用字符来表示数据类型
例如,要将变量“bookName”声明为字符串类型,可以用如下的代码来表示。
Dim bookName$
3.2.4 变量的作用域
变量的值保存在内存中,内存是一个暂时存储数据的地方,因此变量是有其自身的生存周期。变量的作用范围就是变量的作用域。根据变量的生存周期,变量被分为过程级变量、模块级变量、全局变量和静态变量。一般来说变量在哪个部分定义,那么变量就在哪个部分起作用。
● 过程级变量:在过程中声明,其作用范围是在变量所在的过程中。
● 模块级变量:在过程外声明,其作用范围是在变量所在的模块中。
● 全局变量:在过程外声明,其作用范围是在应用程序的所有模块的过程中。
● 静态变量:通常在过程中声明,其作用范围是在变量所在的过程中。但是过程结束后,其值仍旧会被保留。
1. 过程级变量
在VBA编程中,这类变量使用得最多,变量声明的位置是在Sub或者Function过程内,变量起作用的位置也位于过程内。可以在不同的过程中声明具有相同名称的变量。
例3-07:在模块中输入如下代码,两个过程内都使用了一个名为a的变量,输入完代码后,先运行“测试1”过程,再运行“测试2”过程,请判断运行完测试2后,消息框会显示的值。
#001: Sub测试1() #002: Dim a As Integer #003: a = 100 #004: End Sub #005: #006: Sub测试2() #007: Dim a As Integer #008: a = a + 50 #009: MsgBox a #010: End Sub
首先运行名为“测试1”的过程,然后再运行名为“测试2”的过程,显示的消息框中值为50。这是因为在第2行代码声明了一个名为a的变量,其声明范围在过程中,是一个过程级变量,因此其起作用的范围就在“测试1”过程中。当“测试1”过程运行结束后,该变量就完成了其生存周期,不再有作用。
接着运行“测试2”过程,在这个过程中也有一个名为a的变量,虽然和“测试1”过程中的变量名称相同,实际上它们是两个不同的变量。这好比同名的两个人,虽然他们的名字相同,但是并不意味着他们就是同一个人。第8行代码计算的结果就是50,导致最终消息框显示的结果也是50。
2. 模块级变量
如果将声明变量的位置放置在模块的所有过程外,那么此时变量可以起作用的范围就是变量声明所在的模块中。在模块级中声明变量的时候除了可以使用Dim外,还可以使用Private进行声明,两者的效果是一致的。
例3-08:在模块中输入如下代码,将变量a放置在两个过程外。输入完代码后,先运行“测试1”过程,再运行“测试2”过程,请判断运行完测试2后,消息框会显示的值。
#001: Dim a As Integer #002: Sub测试1() #003: a = 100 #004: End Sub #005: #006: Sub测试2() #007: a = a + 50 #008: MsgBox a #009: End Sub
首先运行名为“测试1”的过程,然后再运行名为“测试2”的过程,显示的消息框中值为150。在第1行代码完成了变量a的声明过程,由于变量a放置在所有的模块外,那么这个变量将对位于本模块中所有的变量都起作用。运行完“测试1”过程后,变量a并没有结束其生存周期,当运行“测试2”过程的时候,变量仍旧在起作用,因此最终执行的结果是弹出一个消息框,其内容为150。
3. 全局变量
能在所有的模块中都起作用的变量是全局变量。声明全局变量的时候需要使用关键字Public。
例3-09:假设在VBA中有两个模块,分别是模块1和模块2,在模块1中输入如下代码:
#001: Dim a As Integer #002: Sub测试1() #003: a = 100 #004: End Sub
在模块2中输入如下的代码
#005: Sub测试2() #006: a = a + 50 #007: MsgBox a #008: End Sub
输入完代码后,先运行模块1中的“测试1”过程,再运行模块2中的“测试2”过程,请判断运行完测试2后,消息框会显示的值。
首先运行名为“测试1”的过程,然后再运行名为“测试2”的过程,显示的消息框中值为150。第1行代码声明了一个名为a的全局变量,该变量将在所有的模块中起作用。执行完模块1中的“测试1”过程后,变量a的值100被保留,接着执行模块2中“测试2”过程时,变量a的值被接着用于相加,上述代码因此最终执行的结果是弹出一个消息框,其内容为150。
4. 静态变量
在过程中用Dim声明的变量会随着过程的结束而失去效用。特殊情况下如果将这个变量用Static进行声明,将其声明为Static静态变量,那么随着过程的结束,变量的值仍旧会予以保存。
例3-10:在模块中输入如下的代码,反复执行下述代码,观察消息框所显示的值。
#001: Sub静态变量演示() #002: Static X As Integer #003: MsgBox "X = " & X #004: X = X + 1 #005: End Sub
第一次运行这个过程,消息框显示的值是0,再次执行这个过程,消息框中显示的值为1,第三次执行这个过程,消息框中的值显示为2。多次执行“静态变量演示”,每次过程执行完毕后,其值总会比原先运行结果上加1。
产生这种现象的原因就在于,将变量X声明为静态变量后,即使过程运行完毕,X的值对变量所在的过程“静态变量演示”仍旧会发挥作用。当再次运行“静态变量演示”这个过程时,上次运行的X的值又接着参与运算,导致每次过程执行完毕后,其值总会比原先运行结果上加1。
说明
静态变量和模块级变量是不同的,静态变量只对原先声明它的过程有效。例如上述代码中,静态变量只是对“静态变量演示”这个过程有效,一旦不是这个过程,变量就不再发挥作用。而模块级变量则对该模块下的所有变量都有效。
如果将Sub过程声明为Static类型,那么该过程中声明的变量也就转变为静态变量。在模块中输入下述代码,两者的运行结果是相同的。
Static Sub对比演示() Dim X As Integer MsgBox "X = " & X X = X + 1 End Sub
3.2.5 常量
变量在代码执行的过程中其值会发生变化,而常量在执行的过程中,值不会发生变化。定义常量有助于对代码的理解和今后修改代码。常量可以分为一般常量和符号常量。
● 一般常量是指在代码中直接给出数值的常量。这些常量可以由字符串、数值、逻辑值、日期等组成。
● 符号常量是在代码中使用一些容易记忆的字母组合等来表示常量的值。VBA中最常用的符号常量就是系统内部定义的常量。
用户在编程过程中会使用到许多Excel或者VBA预先定义好的符号常量。VBA内部定义的常量通常以“vb”开头,而Excel内部的常量则通常以“xl”开头。
1. 常量的声明方式
常量的命名方式和变量相同,可以由不超过255个字节的字母、数字和某些特定的符号组成,并且不区分大小写。VBA中的关键字不能作为常量名称使用。常量也可以使用中文来表示。
常量的声明需要使用Const关键字。其语法结构为
[Publict|Private] Const常量名 [As数据类型]=表达式
如果要在一行内声明多个常量,则需要将不同的常量用逗号隔开。
例如声明某个常量的值为100通常有如下的方式。
● Const myNum As Integer = 100
● Const myNum = 100
在代码窗口输入下述代码,下述代码使用了Const声明常量圆周率。
#001: Sub圆形面积和周长() #002: Dim zc As Single #003: Dim mj As Single #004: Dim r As Single #005: Const pi = 3.14 #006: r = 5 #007: zc = 2 * pi * r #008: mj = pi * r * r #009: End Sub
在上述代码中使用pi作为圆周率的代称,显然比在代码中到处使用3.14圆周率的具体数值来得方便。而且如果今后要采用更加精确的圆周率的值,那么只需要更改第5行代码即可。
2. 常量的作用范围
和变量存在作用域一样,常量也有作用范围。包括了过程级、模块级和公有级别的常量。
● 过程级:在过程内声明的常量,只在本过程内部起作用。
● 模块级:在过程外声明,能对常量所在的模块起作用。
● 公有级:在过程外使用Public关键字进行声明的常量。能够对程序所有的模块都起作用。
各级别的常量起作用方式和变量的作用域类似。