语法
[Private | Public | Friend] [Static] Sub name [(arglist)]
[statements]
[Exit Sub]
[statements]
End Sub
* 用[]符号括起来的选项是可选的。
前面这3个[Private | Public | Friend]是同作用范围有关的。Private表示私有,即是这个过程只能从本模块里面调用。使用了这个的话,你从菜单"工具"->"宏"->"宏..."里看不到这个过程。Public表示公用,这样你从其它的模块也可以访问这个公用过程。如果前面没有任何[Private | Public | Friend]的话,过程默认是公用的。公用的过程可以从菜单"工具"->"宏"->"宏..."里看得到。Friend是用在类模块里面的,比较少用,就不说了。
语法
[Private | Public | Friend] [Static] Sub name [(arglist)]
[statements]
[Exit Sub]
[statements]
End Sub
* 用[]符号括起来的选项是可选的。
前面这3个[Private | Public | Friend]是同作用范围有关的。Private表示私有,即是这个过程只能从本模块里面调用。使用了这个的话,你从菜单"工具"->"宏"->"宏..."里看不到这个过程。Public表示公用,这样你从其它的模块也可以访问这个公用过程。如果前面没有任何[Private | Public | Friend]的话,过程默认是公用的。公用的过程可以从菜单"工具"->"宏"->"宏..."里看得到。Friend是用在类模块里面的,比较少用,就不说了。
Static是静态的意思,你可能还记得用Static声明静态变量,用它声明过程的话,表示这个过程里面声明的局部变量在下次调用这个过程时仍然保持它的值。
下面是Static声明过程的用法. 运行try1过程,然后可以在立即窗口里看到结果。
Static Sub m1()
Dim i As Integer
Dim j As Integer
i = i + 1
j = j + 1
Debug.Print "i=" & i & " j=" & j
End Sub
Private Sub m2()
Dim i As Integer
Dim j As Integer
i = i + 1
j = j + 1
Debug.Print "i=" & i & " j=" & j
End Sub
Sub try1()
Dim i As Integer
Debug.Print "静态过程:"
For i = 1 To 10
Call m1
Next i
Debug.Print "私有过程:"
For i = 1 To 10
Call m2
Next i
End Sub
如果没有使用 Public、Private 或 Friend 显式指定,Sub 过程按缺省情况就是公用的。如果没有使用 Static,则在调用之后不会保留局部变量的值。Friend 关键字只能在类模块中使用。不过 Friend 过程可以被工程的任何模块中的过程访问。Friend 过程不会在其父类的类型库中出现,且 Friend 过程不能被后期绑定。
小心 Sub 过程可以是递归的;也就是说,该过程可以调用自己来完成某个特定的任务。不过,递归可能会导致堆栈上溢。通常 Static 关键字和递归的 Sub 过程不在一起使用。
所有的可执行代码都必须属于某个过程。不能在别的 Sub、Function 或 Property 过程中定义 Sub 过程。
Exit Sub 语句使执行立即从一个 Sub 过程中退出。程序接着从调用该 Sub 过程的语句下一条语句执行。在 Sub 过程的任何位置都可以有 Exit Sub 语句。
Sub 过程与 Function 过程的相似之处是:它们都一个可以获取参数,执行一系列语句,以及改变其参数的值的独立过程。而与 Function 过程不同的是:带返回值的 Sub 过程不能用于表达式。
可以使用过程名并后跟相应的参数列表来调用一个 Sub 过程。请参阅 Call 语句关于如何调用 Sub 过程的详细的说明信息。
在 Sub 过程中使用的变量分为两类:一类是在过程内显式定义的,另一类则不是。在过程内显式定义的变量(使用 Dim 或等效方法)都是局部变量。对于使用了但又没有在过程中显式定义的变量,除非其在该过程外更高级别的位置有显示地定义,否则也是局部的。
小心 过程可以使用没有在过程内显式定义的变量,但只要有任何在模块级别定义的名称与之同名,就会产生名称冲突。如果过程中使用的未定义的变量与别的过程,常数,或变量的名称相同,则认为过程使用的是模块级的名称。显式定义变量就可以避免这类冲突。可以使用 Option Explicit 语句来强制显式定义变量。
注意 不能使用 GoSub、GoTo 或 Return 来进入或退出 Sub 过程。
现在说说arglist, 它的语法如下:
[Optional] [ByVal | ByRef] [ParamArray] varname[( )] [As type] [= defaultvalue]
先说Optional,Optional表示这个参数是可选的,意思是在调用过程时可以不传递值也可以传递值给这个参数. 如果有给出defaultvalue给这个参数时(如optional iInput2 As Integer=13), 当调用过程没有传递值给这个参数时, 过程里面会默认使用这个defaultvalue.
Optional必须对最后面的那些参数使用,也就是说这个参数用了Optional后,后面的参数就必须也使用Optional.
Sub mmm(iInput1 As Integer, Optional iInput2 As Integer = 13, Optional iInput3 As Integer) 'iInput2用了Optional后,iInput3也必须用Optional
MsgBox "iInput1=" & iInput1 & vbCrLf & "iInput2=" & iInput2 & vbCrLf & "iInput3=" & iInput3
End Sub
Sub subTry()
Call mmm(23, 34, 2) '可以给3个参数都赋值
Call mmm(23, , 2) '也可以给第3个赋值,而不给第2个参数赋值,这样iInput2会等于默认值13
Call mmm(23, 34) '可以给第2个参数都赋值而不给第3个参数赋值
Call mmm(23) '第2个,第3个参数都不赋值
End Sub
ParamArray的用法
ParamArray只用于 arglist 的最后一个参数,指明最后这个参数是一个包含Variant类型 元素的 Optional 数组,但你传递值给过程时还是使用逗号分开多个参数,过程里面会把找几个参数合并成一个数组。使用 ParamArray 的好处是你可以提供不定数目不定类型的参数给过程。ParamArray不能与 ByVal,ByRef,或 Optional 一起使用。
Sub m1(iInput1 As Integer, ParamArray argArr())
Dim strList As String
Dim i As Integer
strList = "iInput1=" & iInput1 & vbCrLf
For i = 0 To UBound(argArr)
On Error Resume Next
strList = strList & "argArr(" & i & ")=" & argArr(i) & vbCrLf
If Err.Description <> "" Then
strList = strList & "argArr(" & i & ")=missing para" & vbCrLf
Err.Clear
End If
Next i
MsgBox strList
End Sub
Sub try1()
Call m1(23, 24, 25)
Call m1(23, 24, , 25)
Call m1(23, 24, 64.4, 25, "data") '这后面的参数可以再加
End Sub
ByVal和ByRef的用法. VBA里默认是ByRef的。ByVal的意思是按值传递参数,因为是按值传递,这个参数在过程里面的值有变化的话它影响的范围只是在这个过程里面。出了过程就没有用了。而ByRef是按地址或者说按引用传递,传递个过程的实际是这个数值的地址,而不是值本身,在过程里面对这个参数做改变的话是对这个地址的值改变,这样在过程外面也可以看到这个值变了。运行下面的例子可以看到不同的。
Sub mmm(ByVal iI1 As Integer, iI2 As Integer)
iI1 = iI1 + 10
iI2 = iI2 + 10
MsgBox "Inside: iI1=" & iI1 & " iI2=" & iI2
End Sub
Sub mySub()
Dim iI1 As Integer
Dim iI2 As Integer
iI1 = 10
iI2 = 12
MsgBox "Before: iI1=" & iI1 & " iI2=" & iI2
Call mmm(iI1, iI2)
MsgBox "After: iI1=" & iI1 & " iI2=" & iI2
End Sub