变量、常数和数据类型概述
在 Visual Basic 环境下进行计算时,常常需要临时存储数据。例如,可能想要计算几个值,将它们进行比较,并根据比较的结果对它们进行不同的操作。如果想要比较这些值,就要存储它们,但不必把它们存入属性。像大多数编程语言那样,Visual Basic 使用变量来存储值。变量具有名字(用来引用该变量所含的值的名词)和数据类型(确定变量可以存储的数据的种类)。数组可以用来存储建立了索引的相关变量集。
常数也存储数值,顾名思义,在整个应用程序执行过程中,这些值都保持不变。常数的使用增加了代码的可读性,因为我们看到的是具有含义的名字而不是数字。Visual Basic 有许多内部常数,但也可以建立自定义常数。
在 Visual Basic 中,数据类型控制了数据的内部存储。按照缺省规定,VisualBasic 使用了变体数据类型。在不需要 Variant 提供的灵活性时,还有许多其它可用的数据类型,它们可用来优化代码的速度和大小。
变量
在 Visual Basic 中执行应用程序期间,用变量临时存储数值。变量具有名字(用来引用变量所包含的值的词)和数据类型(确定变量能够存储的数据的种类)。
可以把变量看作内存中存放未知值的所在处。例如,假定正在为水果铺编一个销售苹果的软件。在销售实际发生之前并不知道苹果的价格和销量。此时,可以设计两个变量来保存未知数,将它们命名为 ApplePrice 和ApplesSold。每次运行程序时,用户就这两个变量提供具体值。为了计算总的销售额,并且将结果显示在名叫 txtSales 的文本框中,代码应该是这样的:
txtSales.txt = ApplePrice * ApplesSold
每次根据用户提供的数值,这个表达式返回不同的金额。由于有了变量,就可以设计一个算式,而不必事先知道实际的输入是多少。
在这个例子中,ApplePrice 的数据类型是货币,而 ApplesSold 的数据类型是整数。变量还可以表示许多其它数值,比如:文本数值、日期、各种数值类型,甚至对象也在此列。
存储和检索变量中的数据
用赋值语句进行计算,并将结果赋予变量:
ApplesSold = 10 '将值 10
'传给变量。
ApplesSold = ApplesSold + 1
'变量值
'增一。
注意,例子中的等号是赋值符,并不是等于操作符;它将数值 (10) 赋予变量 (ApplesSold)。
声明变量
声明变量就是事先将变量通知程序。要用 Dim 语句声明变量,Dim 语句提供了变量名:
Dim variablename [As type]
在过程内部用 Dim 语句声明的变量,只有在该过程执行时才存在。过程一结束,该变量的值也就消失了。此外,过程中的变量值对过程来说是局部的,也就是说,无法在一个过程中访问另一个过程中的变量。由于这些特点,在不同过程中就可使用相同的变量名,而不必担心有什么冲突和意想不到变故。
变量名:
1.必须以字母开头。
2.不能包含嵌入的(英文)句号或者嵌入的类型声明字符。
3.不得超过 255 个字符。
4.在同一个范围内必须是唯一的。范围就是可以引用变量的变化域,如一个过程、一个窗体等等。
由于 Dim 语句中的可选的 As type 子句,可以定义被声明变量的数据类型或对象类型。数据类型定义了变量所存储信息的类型。String、Integer 和Currency 都是数据类型的例子。变量也可以包含来自Visual Basic或其它应用程序的对象。Object、Form1 和 TextBox 都是 Visual Basic 对象类型或类的实例。
详细信息 关于对象的更详细的信息,请参阅第九章“用对象编程”和第十章“用部件编程”。在本章后面的“数据类型”部分将详细讨论数据类型。声明变量的其它方式:
不在过程内部,而在窗体、标准或类模块的声明段声明变量,这将使变量对模块中的所有过程有效。
用 Public 关键字声明变量,这将使变量在整个应用程序中有效。
用 Static 关键字声明一个局部变量,那么,即使过程结束,变量的值也仍然保留着。
隐式声明
在使用一个变量之前并不必先声明这个变量。例如,可以书写这样一个函数,在其中就不必在使用变量 TempVal 之前先声
明它:
Function SafeSqr (num)
TempVal = Abs (num)
SafeSqr = Sqr (TempVal)
End Function
Visual Basic 用这个名字自动创建一个变量,使用这个变量时,可以认为它就是显式声明的。虽然这种方法很方便,但是如果把变量名拼错了的话,会导致一个难以查找的错误。例如,假定写了这样一个函数:
Function SafeSqr (num)
TempVal = Abs (num)
SafeSqr = Sqr (TemVal)
End Function
乍看起来,这两段代码好像是一样的。但是因为在倒数第二行把 TempVal 变量名写错了,所以函数总是返回 0。当 Visual Basic 遇到新名字,它分辨不出这是意味着隐式声明了一个新变量呢,还是仅仅把一个现有变量名写错了,于是只好用这个名字再创建一个新变量。
显式声明
为了避免写错变量名引起的麻烦,可以规定,只要遇到一个未经明确声明就当成变量的名字,Visual Basic 都发出错误警告。要显式声明变量,请
在类模块、窗体模块或标准模块的声明段中加入这个语句:
Option Explicit
-或-
在“工具”菜单中选取“选项”,单击“编辑器”选项卡,再复选“要求变量声明”选项。这样就在任何新模块中自动插入 Option Explicit 语句,但不会在已经建立起来的模块中自动插入;所以在工程内部,只能用手工方法向现有模块添加 Option Explicit。
如果对包含 SafeSqr 函数的窗体或标准模块执行该语句,那么 Visual Basic将认定 TempVal 和 TemVal 都是未经声明变量,并为两者都发出错误信息。随后就可以显式声明 TempVal。
Function SafeSqr (num)
Dim TempVal
TempVal = Abs (num)
SafeSqr = Sqr (TemVal)
End Function
因为 Visual Basic 对拼错了的 TemVal 显示错误信息,所以能够立刻明白是什么问题。由于 Option Explicit 语句有助于抓住这些类型的错误,所以最好在所有代码中使用它。
注意 Option Explicit 语句的作用范围仅限于语句所在模块,所以,对每个需要 Visual Basic 强制显式变量声明的窗体模块、标准模块及类模块,必须将 Option Explicit 语句放在这些模块的声明段中。如果选择“要求变量声明”,Visual Basic 会在后续的窗体模块、标准模块及类模块中自动插入 Option Explicit,但是不会将它加入到现有代码中。必须在工程中通过手工将 Option Explicit 语句加到任何现有模块中。
理解变量的范围
变量的范围确定了能够知晓该变量存在的那部分代码。在一个过程内部声明变量时,只有过程内部的代码才能访问或改变那个变量的值;它有一个范围,对该过程来说是局部的。但是,有时需要使用具有更大范围的变量,例如这样一个变量,其值对于同一模块内的所有过程都有效,甚至对于整个应用程序的所有过程都有效。Visual Basic 允许在声明变量时指定它的范围。
指定变量的有效范围
一个变量在划定范围时被看作是过程级(局部)变量,还是模块级变量,这取决于声明该变量时采用的方式。
过程级变量只有在声明它们的过程中才能被识别,它们又称为局部变量。用 Dim 或者 Static 关键字来声明它们。例如:
Dim intTemp As Integer
- 或者 -
Static intPermanent As Integer
在整个应用程序运行时,用 Static 声明的局部变量中的值一直存在,而用Dim 声明的变量只在过程执行期间才存在。
对任何临时计算来说,局部变量是最佳选择。例如,可以建立十来个不同的过程,每个过程都包含称作 intTemp 的变量。只要每个 intTemp 都声明为局部变量,那么每个过程只识别它自己的 intTemp 版本。任何一个过程都能够改变它自己的局部的 intTemp 变量的值,而不会影响别的过程中的intTemp 变量。
模块内部使用的变量
按照缺省规定,模块级变量对该模块的所有过程都可用,但对其它模块的代码不可用。可在模块顶部的声明段用 Private 关键字声明模块级变量,从而建立模块级变量。例如:
Private intTemp As Integer
在模块级,Private 和 Dim 之间没有什么区别,但 Private 更好些,因为很容易把它和 Public 区别开来,使代码更容易理解。
所有模块使用的变量
为了使模块级的变量在其它模块中也有效,用 Public 关键字声明变量。公用变量中的值可用于应用程序的所有过程。和所有模块级变量一样,也在模块顶部的声明段来声明公用变量。例如:
Public intTemp As Integer
注意 不能在过程中声明公用变量,只能在模块的声明段中声明公用变量。
详细信息 有关变量的其它信息,请参阅 “高级变量主题”。
高级变量主题>>
使用多个同名的变量
如果不同模块中的公用变量使用同一名字,则通过同时引用模块名和变量名就可以在代码中区分它们。例如,如果有一个在 Form1 和 Module1 中都声明了的公用 Integer 变量 intX,则把它们作为 Module1.intX 和Form1.intX 来引用便得到正确值。
为了看清这是如何工作的,在一个新工程中插入两个标准模块,并在窗体上画上三个命令按钮。
在第一个标准模块 Module1 之中声明一个变量 intX。Test 过程设置它的值:
Public intX As Integer '声明 Module1 的 intX。
Sub Test ()
'设置 Module1 的 intX 变量的值。
intX = 1
End Sub
在第二个标准模块 Module2 中声明了第二个变量 intX,它有相同的名字。又是名为 Test 的过程设置它的值:
Public intX As Integer '声明 Module2 的 intX。
Sub Test ()
'设置 Module2 的 intX 变量的值。
intX = 2
End Sub
在窗体模块中声明了第三个变量 intX。名为 Test 的过程又一次设置它的值。
Public intX As Integer '声明了该窗体的 intX 变量。
Sub Test ()
' 设置 form 中的 intX 变量值。
intX = 3
End Sub
在三个命令按钮的 Click 事件过程中,每一个都调用了相应的 Test 过程,并用 MsgBox 来显示这三个变量的值。
Private Sub Command1_Click ()
Module1.Test ' 调用 Module1 中的 Test。
MsgBox Module1.intX ' 显示 Module1 的 intX。
End Sub
Private Sub Command2_Click ()
Module2.Test ' 调用 Module2 中的 Test。
MsgBox Module2.intX ' 显示 Module2 的 intX。
End Sub
Private Sub Command3_Click ()
Test ' 调用 Form1 中的 Test。
MsgBox intX' 显示 Form1 的 intX。
End Sub
运行应用程序,单击三个命令按钮中的每一个按钮。于是将看到三个公用变量被分别引用。注意在第三个命令按钮的 Click 事件过程中,在调用Form1 的 Test 过程时不必指定 Form1.Test,在调用 Form1 的 Integer 变量的值时也不必指定 Form1.intX 。如果多个过程或变量同名,则 VisualBasic 会取变化更受限制的值,在本例中就是 Form1 变量。
公用变量与局部变量的比较
在不同的范围内也可有同名的变量。例如,可有名为 Temp 的公用变量,然后在过程中声明名为 Temp 的局部变量。在过程内通过引用名字 Temp来访问局部变量;而在过程外则通过引用名字 Temp 来访问公用变量。通过用模块名限定模块级变量就可在过程内访问这样的变量。
Public Temp As Integer
Sub Test ()
Dim Temp As Integer
Temp = 2 ' Temp 的值为 2。
MsgBox Form1.Temp ' Form1.Temp 的值为 1。
End Sub
Private Sub Form_Load ()
Temp = 1 ' 将 Form1.Temp 的值设置成 1。
End Sub
Private Sub Command1_Click ()
Test
End Sub
一般说来,当变量名称相同而范围不同时,局限性大的变量总会用“阴影”遮住局限性不太大的变量(即优先访问局限性大的变量)。所以,如果还有名为 Temp 的过程级变量,则它会用“阴影”遮住模块内部的公用变量Temp。
阴影窗体属性和控件
由于阴影效应,窗体属性、控件、常数和过程皆被视为窗体模块中的模块级变量。窗体属性或控件的名称与模块级变量、常数、自定义类型或过程的名称相同是不合法的,因为它们的范围相同。
在窗体模块内,和窗体中控件同名的局部变量将遮住同名控件。因此必须引用窗体名称或 Me 关键字来限定控件,才能设置或者得到该控件的值或它的属性值。例如:
Private Sub Form_Click ()
Dim Text 1 , BackColor
'假定该窗体有一个控件也叫做 Text1。
Text1 = "Variable" '变量用“阴影”遮住控件。
Me.Text1 = "Control" '要得到控件,必须用‘Me’限定。
Text1.Top = 0 '导致出错!
Me.Text1.Top = 0 '要得到控件,必须用‘Me’限定。
BackColor = 0 '变量用“阴影”遮住属性。
Me.BackColor = 0 '要得到窗体属性,必须用‘Me’限定。
End Sub
使用同名的变量和过程
专用模块级变量和公共模块级变量的名字也会和过程名冲突。模块中的变量不能和任何过程同名,也不能和模块中定义的类型同名。但可以和公用过程或其它模块中定义的类型或变量同名。在这种情况下,从别的模块访问这个变量时,就必须用模块名来限定。
虽然上面讨论阴影规则并不复杂,但是用阴影的方法可能会带来麻烦,而且会导致难以查找的错误。因此,对不同的变量使用不同的名称才是一种好的编程习惯。在窗体模块中应尽量使变量名和窗体中的控件名不一样。
静态变量
除范围之外,变量还有存活期,在这一期间变量能够保持它们的值。在应用程序的存活期内一直保持模块级变量和公用变量的值。但是,对于 Dim 声明的局部变量以及声明局部变量的过程,仅当过程在执行时这些局部变量才存在。通常,当一个过程执行完毕,它的局部变量的值就已经不存在,而且变量所占据的内存也被释放。当下一次执行该过程时,它的所有局部变量将重新初始化。
但可将局部变量定义成静态的,从而保留变量的值。在过程内部用 Static 关键字声明一个或多个变量,其用法和 Dim 语句完全一样:
Static Depth
例如,下面的函数将存储在静态变量 Accumulate 中的以前的运营总值与一个新值相加,以计算运营总值。
Function RunningTotal (num)
Static ApplesSold
ApplesSold = ApplesSold + num
RunningTotal = ApplesSold
End Function
如果用 Dim 而不用 Static 声明 ApplesSold,则以前的累计值不会通过调用函数保留下来,函数只会简单地返回调用它的那个相同值。
在模块的声明段声明 ApplesSold,并使它成为模块级变量,由此也会收到同样效果。但是,这种方法一旦改变变量的范围,过程就不再对变量排他性存取。由于其它过程也可以访问和改变变量的值,所以运营总值也许不可靠,代码将更难于维护。
声明所有的局部变量为静态变量
为了使过程中所有的局部变量为静态变量,可在过程头的起始处加上 Static关键字。例如:
Static Function RunningTotal (num)
这就使过程中的所有局部变量都变为静态,无论它们是用 Static、Dim 或Private 声明的还是隐式声明的。可以将 Static 放在任何 Sub 或 Function过程头的前面,包括事件过程和声明为 Private 的过程。