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. React之JSX语法

    1. JSX的介绍   JSX(JavaScript XML)——一种在React组件内部构建标签的类XML语法.react在不使用JSX的情况下一样可以工作,然而使用JSX可以提高组件的可读性,因此 ...

  2. 并发-Synchronized底层优化(偏向锁、轻量级锁)

    Synchronized底层优化(偏向锁.轻量级锁) 参考: http://www.cnblogs.com/paddix/p/5405678.html 一.重量级锁 上篇文章中向大家介绍了Synchr ...

  3. 利用war包和Tomcat镜像创建Web镜像

      from hub.c.163.com/library/tomcat:tag #代表以tomcat镜像为基础 MAINTAINER huhuixin 18611551449@163.com #代表所 ...

  4. Spring中Value注解的使用

    Spring中Value注解的使用 分类: Spring2014-08-16 17:28 2985人阅读 评论(0) 收藏 举报 有的时候我们定义了Properties文件,并且使用Spring的Pr ...

  5. 网络数据包头部在linux网络协议栈中的变化

    接收时使用skb_pull()不断去掉各层协议头部:发送时使用skb_push()不断添加各层协议头部. 先说说接收: * eth_type_trans - determine the packet' ...

  6. Hibernate缓存何时使用和如何使用

    http://developer.51cto.com/art/201202/315922.htm 1. 关于hibernate缓存的问题: 1.1. 基本的缓存原理 Hibernate缓存分为二级, ...

  7. Codeforces Beta Round #17 D.Notepad 指数循环节

    D. Notepad time limit per test 2 seconds memory limit per test 64 megabytes input standard input out ...

  8. LeetCode第[17]题(Java):Letter Combinations of a Phone Number

    题目:最长公共前缀 难度:EASY 题目内容: Given a string containing digits from 2-9 inclusive, return all possible let ...

  9. Ajax-06 Ajax数据交换格式

    1.数据交换格式 服务端返回的数据,在本质上都是字符串,只是原生Ajax 或jQuery Ajax将这些字符串转换为容易理解的各种常用格式. a. Text 文本字符串 b.  XML JavaScr ...

  10. 51nod 1406 位运算/dp

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1406 1406 与查询 题目来源: CodeForces 基准时间限制: ...