VBA的过程及参数详解

VBA中的过程(Procedure)有两种,一种叫函数(Function),另外一种叫子程序(Subroutine),分别使用Function和Sub关键字。它们都是一个可以获取参数、执行一系列语句、以及改变其参数的值的独立过程。而与 Function 过程不同的是:带返回值的 Sub 过程不能用于表达式。

这里主要介绍子程序的使用方法,同样这些方法也可以应用到Function上。

语法

[Private | Public | Friend] [Static] Sub name [(arglist)]
[statements]
[Exit Sub]
[statements]
End Sub
* 用[]符号括起来的选项是可选项

[Private | Public | Friend]
这三个关键字与作用范围有关。
Private表示私有,即这个过程只能从本模块里面调用。使用这个关键字,从菜单“工具”->”宏”->”宏…”中将看不到该过程。
Public表示公用,这样从其它的模块也可以访问这个过程。如果没有使用 Public、Private 或 Friend 显式指定,Sub 过程按缺省情况就是公用的。公用的过程可以从菜单”工具”->”宏”->”宏…”中看到。
Friend用在类模块里面,较少使用,在此就不介绍了。

Static是静态的意思(你可能还记得用Static声明静态变量),用它声明过程的话,表示这个过程中声明的局部变量在下次调用这个过程时仍然保持它原来的值。
下面是Static声明过程的用法。

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

运行try1过程,然后可以在立即窗口里看到结果。
=

下面是一些使用过程时需要注意到地方。

  • Sub过程可以是递归的;也就是说,该过程可以调用自己来完成某个特定的任务。不过,递归可能会导致堆栈上溢。通常 Static 关键字和递归的 Sub 过程不在一起使用。
  • 所有的可执行代码都必须属于某个过程。不能在别的 Sub、Function 或 Property 过程中定义 Sub 过程。
  • Exit Sub 语句使执行立即从一个 Sub 过程中退出。程序接着从调用该 Sub 过程的语句下一条语句执行。在 Sub 过程的任何位置都可以有 Exit Sub 语句。
  • 在Sub过程中使用的变量分为两类:一类是在过程内显式定义的,另一类则不是。在过程内显式定义的变量(使用 Dim或等效方法)都是局部变量。对于使用了但又没有在过程中显式定义的变量,除非其在该过程外更高级别的位置有显示地定义,否则也是局部的。
  • 小心过程可以使用没有在过程内显式定义的变量,但只要有任何在模块级别定义的名称与之同名,就会产生名称冲突。如果过程中使用的未定义的变量与别的过程,常数,或变量的名称相同,则认为过程使用的是模块级的名称。显式定义变量就可以避免这类冲突。可以使用 Option Explicit 语句来强制显式定义变量。
  • 注意:不能使用 GoSub、GoTo 或 Return 来进入或退出 Sub 过程。

参数表arglist

语法:
[Optional] [ByVal | ByRef] [ParamArray] varname[( )] [As type] [= defaultvalue]

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()
' 可以给3个参数都赋值
Call mmm(23, 34, 2) 'iInput=23, iInput2=34, iInput3=2
'也可以给第3个赋值,而不给第2个参数赋值,这样iInput2会等于默认值13
Call mmm(23, , 2) 'iInput=23, iInput2=13, iInput3=2
'可以给第2个参数都赋值而不给第3个参数赋值
Call mmm(23, 34) 'iInput=23, iInput2=34, iInput3=0
' 第2个,第3个参数都不赋值
Call mmm(23) 'iInput=23, iInput2=12, iInput3=0
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 & ")=缺失参数" & vbCrLf
Err.Clear ' 清除错误
End If
Next i
MsgBox strList
End Sub
Sub try1()
Call m1(23, 24, 25) ' iInput=23, argArr(0)=24, argArr(1)=25
Call m1(23, 24, , 25) ' iInput=23, argArr(0)=24, argArr(1)=缺失参数, argArr(2)=25
Call m1(23, 24, 64.4, 25, "data") ' iInput=23, argArr(0)=24, argArr(1)=64.4, argArr(2)=25, argArr(3)=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
' 按顺序分别显示
' 显示 Before: iI1=10 iI2=12
' 显示 Before: iI1=20 iI2=22
' 显示 Before: iI1=10 iI2=22
' 过程mmm中修改了iI1和iI2,但是iI1是按值传递,在mmm过程之外的iI1并受影响
' 而iI2是按引用传递,mmm过程之外的iI2也被改变了
End Sub

另外,如果参数是数组的话,只能使用按引用传递,因为传递的实际上是数组第一个元素的地址。例如下面代码的用法。

Sub GetArray(arrTemp() As Integer)
Dim i As Integer
For i = 0 To UBound(arrTemp)
Debug.Print "Item " & i & ": " & arrTemp(i)
Next i
End Sub
Sub PassArray()
Dim arrInt(3) As Integer
arrInt(0) = 1
arrInt(1) = 2
arrInt(2) = 3
arrInt(3) = 4
Call GetArray(arrInt)
' 在立即窗口打印出
' Item 0: 1
' Item 1: 2
' Item 2: 3
' Item 3: 4
End Sub

但对于对象来说,使用ByVal实际上传递的仍然是对对象的引用,这样在过程中对象的修改将会影响过程外部对象的值或属性。如果使用ByVal,而在过程中创建一个新的对象实例,将该对象赋值给传递的对象,则不影响调用对象的外部的属性或值。而如果使用ByRef,在过程中创建一个新的对象实例,将该对象赋给传递的对象,却会影响过程外该对象的属性或值。

Sub TestByValByRef()
Dim objDic As Object
 
Set objDic = CreateObject("Scripting.Dictionary")
objDic(1) = 100
Debug.Print "byValueTest1"
Debug.Print "原始值: objDic(1)=" & objDic(1)
Call byValTest1(objDic)
Debug.Print "外部值: objDic(1)=" & objDic(1) & vbCrLf
 
objDic(1) = 100
Debug.Print "byValueTest2"
Debug.Print "原始值: objDic(1)=" & objDic(1)
Call byValTest2(objDic)
Debug.Print "外部值: objDic(1)=" & objDic(1) & vbCrLf
 
objDic(1) = 100
Debug.Print "byRefTest"
Debug.Print "原始值: objDic(1)=" & objDic(1)
Call byRefTest(objDic)
Debug.Print "外部值: objDic(1)=" & objDic(1)
End Sub
Private Sub byValTest1(ByVal c As Object)
Dim a As Object
Set a = CreateObject("Scripting.Dictionary")
a(1) = 200
Set c = a
End Sub
Private Sub byValTest2(ByVal c As Object)
c(1) = 200
End Sub
Private Sub byRefTest(ByRef c As Object)
Dim a As Object
Set a = CreateObject("Scripting.Dictionary")
a(1) = 200
Set c = a
End Sub

运行过程TestByValByRef,将在立即窗口打印出下面的结果。

byValueTest1
原始值: objDic(1)=100
外部值: objDic(1)=100

byValueTest2
原始值: objDic(1)=100
外部值: objDic(1)=200

byRefTest
原始值: objDic(1)=100
外部值: objDic(1)=200

出处:http://www.360doc.com/content/10/0112/16/406571_13355136.shtml

VBA的过程及参数详解的更多相关文章

  1. iptables参数详解

    iptables参数详解 搬运工:尹正杰 注:此片文章来源于linux社区. Iptalbes 是用来设置.维护和检查Linux内核的IP包过滤规则的. 可以定义不同的表,每个表都包含几个内部的链,也 ...

  2. mha配置参数详解

    mha配置参数详解: 参数名字 是否必须 参数作用域 默认值 示例 hostname Yes Local Only - hostname=mysql_server1, hostname=192.168 ...

  3. mysqldump的常用语句及各参数详解

    mysqldump的常用语句及各参数详解 分类: MySQL 2011-01-11 17:55 1368人阅读 评论(0) 收藏 举报 数据库mysql服务器tableinsertdatabase m ...

  4. Android 调用图库选择图片实现和参数详解

    //选择图片,调用图库        bt4.setOnClickListener(new OnClickListener() { @Override            public void o ...

  5. Lock_sga 和 pre_page_sga 参数详解

    Lock_sga 和 pre_page_sga 参数详解        Lock_sga 和pre_page_sga,是两个平时用的不算太多的参数,但是这两个参数平时在优化的时候可能给你带来比较乐观的 ...

  6. 机器学习——KMeans聚类,KMeans原理,参数详解

    0.聚类 聚类就是对大量的未知标注的数据集,按数据的内在相似性将数据集划分为多个类别,使类别内的数据相似度较大而类别间的数据相似度较小,聚类属于无监督的学习方法. 1.内在相似性的度量 聚类是根据数据 ...

  7. Spark参数详解 一(Spark1.6)

    Spark参数详解 (Spark1.6) 参考文档:Spark官网 在Spark的web UI在"Environment"选项卡中列出Spark属性.这是一个很有用的地方,可以检查 ...

  8. MySQL复制相关参数详解

    MySQL复制相关参数详解 作者:尹正杰  版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.复制相关系统变量 1>.server_id 是必须设置在master和每个slave上的唯一标 ...

  9. 硬盘SMART检测参数详解[转]

    一.SMART概述        要说Linux用户最不愿意看到的事情,莫过于在毫无警告的情况下发现硬盘崩溃了.诸如RAID的备份和存储技术可以在任何时候帮用户恢复数据,但为预防硬件崩溃造成数据丢失所 ...

随机推荐

  1. MarkDown初学者使用指南

    换MarkDown编辑器了,突然发现自己不会,尴尬!所以顺便总结下Markdown的常用语法 标题 一级标题(格式:#+XXXXX) 二级标题(格式:##+XXXXXX) 三级标题(格式:###+XX ...

  2. 配置zabbix通过微信报警企业微信报警

    如今势态: 报警的方式可谓是八仙过海各显神通,如电话报警,短信报警,邮件报警,QQ报警,微信报警等等. 电话报警:一般都是使用别的平台的工具,平台给你提供一个接口供你使用,大多数为限量收费款 短信报警 ...

  3. Hardware Prefetcher

    硬件预取选项,指CPU有硬件预取功能,在CPU处理指令或数据之前,它将这些指令或数据从内存预取到L2缓存中,借此减少内存读取的时间,帮助消除潜在的瓶颈,以此提高系统效能.通常情况下建议设置为Enabl ...

  4. [CTSC2008]祭祀river

    Description 在遥远的东方,有一个神秘的民族,自称Y族.他们世代居住在水面上,奉龙王为神.每逢重大庆典, Y族都 会在水面上举办盛大的祭祀活动.我们可以把Y族居住地水系看成一个由岔口和河道组 ...

  5. ubuntu 支持中文

    1.cat /usr/share/i18n/SUPPORTED 说明:查看系统支持的字符集,你需要注意的是支持字符集的格式,如对中文会有以下一些显示(我的系统如此,我不知是否普遍) zh_CN.GB1 ...

  6. Word Search, 在矩阵中寻找字符串,回溯算法

    问题描述: Given a 2D board and a word, find if the word exists in the grid. The word can be constructed ...

  7. istringstream 用法

    istringstream 类用于执行C++风格的串流的输入操作 istringstream用空格作为字符串分隔符 #include <iostream>#include <sstr ...

  8. React菜鸟食谱

    JSX 用小括号包裹代码防止分号自动插入的bug,用大括号包裹里面的表达式 切记你使用了大括号包裹的 JavaScript 表达式时就不要再到外面套引号了.JSX 会将引号当中的内容识别为字符串而不是 ...

  9. python学习笔记(arange函数与linspace函数)

    上一篇提及到matplotlib模块.其中会涉及到numpy模块科学计数 这里总结两个数组生成函数 arange 与 linspace: #!/usr/bin/env python # -*- cod ...

  10. shell 数组操作

    1. 定义数组: var_array=(one two three four five) 2.常用操作 获取数组长度: ${#var_array[@]} 获取所有数组元素:  ${var_array[ ...