5.2 接受参数的Sub过程
在调用过程的时候,完全相同代码的过程调用并不常见。常见的情况大多数代码都是相同的,只是某些变量的值有差异。对于这样的情况,就可以考虑让Sub过程接受参数。带参数的Sub过程能够使代码将变得更加的通用。调用带参数的Sub过程除了要指明要调用的Sub过程名外,还要向被调用过程发送参数。
5.2.1 参数传递简介
Sub过程是可以接受参数的,参数类型可以是变量、常量、数组或者对象等。能够接受参数的Sub过程会显得更加的灵活。
例5-02:某客户预计投资5万元国债,每年投资所产生的收益自动滚存购买国债,要求计算在指定收益率和投资年限下的投资总额。
由于国债的收益率和投资年限在测算的时候并不固定,因此在代码中直接将投资收益率和投资年限放入公式计算并不是一种很好的方法。可以用带参数的Sub过程完成投资总额的计算,用其他过程来调用该过程。新建一个模块,在模块中输入代码如下所示。
#001: Sub投资总额(n As Integer, i As Single) #002: Dim val As Single #003: val = Round(50000 * (1 + i) ^ n, 2) #004: MsgBox "投资总额为:" & val & "元" #005: End Sub
第1行代码中,Sub过程声明了两个参数,n表示投资的年限,i表示投资的收益率。第2行代码val表示投资总额。第3行代码提供了投资总额的计算公式。第4行代码用消息框的方式给出了投资总额的大小,Round函数是对运算的结果进行四舍五入。如果直接运行这段代码,则会打开如图5-3所示的宏对话框。
图5-3 宏对话框
由此可见,变量n和i的值由于没有赋具体的值,“投资总额”过程实际上是无法正确运行。解决的方法是用户另外再建一个过程,通过调用“投资总额”过程来达到运行的目的。在调用时,需要向Sub过程中传递参数。
假设用户现在要使用这样一个投资方式,该投资方式下,投资年限为5年,收益率为5%,分别将这两个值输入到A1和B1单元格中,那么可以用下述代码来表示“投资”过程。
#001: Sub投资() #002: Dim n As Integer #003: Dim i As Single #004: n = Range("a1") #005: i = Range("b1") #006: Call投资总额(n, i) #007: End Sub
第2行代码和第3行代码分别声明了变量n和i,分别表示投资年限和年收益率。第4行和第5行代码分别给出了n和i的值从何而来。投资年限的值来自于A1单元格,而年收益率则来自于B1单元格,第6行代码调用了“投资总额”这个Sub过程,调用时向“投资总额”过程中传递了两个参数,分别是n和i,此时n和i都已经有了具体的值。运行“投资”过程,运行的结果如图5-4所示。
图5-4 投资总额
用户如果要更改其他的年限和收益率无需更改代码,只需要将A1和B1单元格中的投资年限和收益率做出修改即可。
说明
在“投资”过程中,传递的参数是两个变量,这两个变量在传递的时候已经有了具体的值。将传递的变量名称和“投资总额”过程中参数的名称定义为一致,是为了提高代码的可理解性,在“投资”过程中,要传递的参数名称也可以用任何合法的变量名称来定义。
5.2.2 参数传递方式
在上例中,“投资”过程向“投资总额”过程参数传递了两个参数。在VBA的参数传递中,一共有两种参数传递方式。
● 按址传递:这是默认的参数传递方式,其他过程可以更改参数的值。
● 按值传递:传递的仅仅是值本身,其他过程无法修改参数的值。
1. 按址传递
例5-03:假设模块中有“按址传递演示”过程和“乘积”过程。“按址传递演示”过程向“乘积”过程传递变量a,变量a的值大小为100,“乘积”过程中将会把传递进来的值乘以10,用消息框显示最终变量a的结果。
#001: Sub按址传递演示() #002: Dim a As Integer #003: a = 100 #004: Call乘积(a) #005: MsgBox a #006: End Sub #007: #008: Sub乘积(b) #009: b = b * 10 #010: End Sub
第4行代码调用了“乘积”过程,并向该过程传递了一个参数a,参数的值为100。运行“按址传递演示”过程,弹出的消息框中看出计算的结果是1000。
按址传递方式中,为变量a赋值100的时候,就在内存的某个地址中建立了一个变量,该变量的值为100,对外的称呼是a。“Call乘积(a)”表示调用“乘积”这个过程的时候传递一个参数,参数传递的时候,是将这个地址传到了“乘积”这个过程,当然“乘积”这个过程将这个地址的对外的称呼叫做b,虽然不同的过程对同一个地址有不同的称呼,但是实际上这些称呼所指向的内存地址并没有变。“乘积”过程对这个地址中的数值进行了一番运算,使得这个地址最终的值为1000。“MsgBox a”的过程就是用消息框将内存中这个地址的值对外公布出去,当然地址中的值已经变成了1000。
2. 按值传递
有的时候并不希望传递出去的值被更改,这就需要在被调用的过程中使用Byval关键字,进行限定。在按值传递方式下,调用过程传递出去的仅仅是值的大小,而非内存中的地址。
例5-04:假设模块中有“按值传递演示”过程和“乘积”过程。“按值传递演示”过程向“乘积”过程传递变量a,变量a的值大小为100,“乘积”过程中将会把传递进来的值乘以10,用消息框显示最终变量a的结果。
#001: Sub按值传递演示() #002: Dim a As Integer #003: a = 100 #004: Call乘积(a) #005: MsgBox a #006: End Sub #007: #008: Sub乘积(ByVal b) #009: b = b * 10 #010: End Sub
这段代码和上例的代码大体相同,所不同的就在于第8行代码,原来的参数被“b”被更改为“ByVal b”,运行“按值传递演示”过程,消息框显示的最终结果是100。
按值传递方式中,“ByVal b”的含义就是按值传递。在“按值传递演示”过程中,变量a被赋值为100,这个过程就是在内存的某个地址中建立了一个变量,该变量的值为100,对外的称呼是a。“Call乘积(a)”表示调用“乘积”这个过程的时候传递一个参数,“乘积(ByVal b)”表示参数传递的时候,不是将地址传到了“乘积”这个过程,而是将值传入了“乘积”过程。“乘积”接收到这个值时,也在内存中用一个地址来存放这个数值,这个地址对外名称是b。当然这个b的地址和“按值传递演示”过程中的变量a的地址实际上并没有关系,是两个不同的地址,只不过初始的值相等。因此“乘积”过程对变量b的运算也就不会影响到变量a的大小。当代码“MsgBox a”最终将内存中名为a的变量值发布出去时,由于该地址中的值没有发生变化,最终结果仍旧是100。
简单地来说Sub过程强调的是执行命令,它运行的结果不会产生值。而Function过程通常被称为自定义函数过程,Function过程运行的结果是会产生值。本章介绍了如何自定义函数的方法以及在VBA中的常用函数。本章还简要介绍了Windows API函数的使用方法。