LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

VBA函数中ByVal和ByRef的区别与应用技巧

admin
2025年1月23日 21:31 本文热度 143

一、ByVal和ByRef基础



ByVal和ByRef是用于限定VBA函数(Function)或子过程(Sub)(以下统称为函数)参数传递方式的关键字。它们决定了在调用函数时,参数是按值传递还是按引用传递。形如:

Function GetName(ByVal a As Integer , ByRef b As Integer) As String

    '代码区

End Function

ByVal(By Value)限定参数a按值传递数据。

ByRef(ByReference)限定参数b按引用传递数据。

在VBA中,ByRef为默认(省略关键字时的)值。如果仅看上面这些一板一眼的说明,对于没有编程基础的人,是非常难理解的。

以下这个test函数使用了ByVal参数和ByRef参数,通过示例mExample过程来展示使用这两个参数传递数据以后发生的变化:

'测试用test函数:

Function test(ByVal myval As Integer, ByRef myref As Integer)

    myval = myval + 10

    myref = myref + 10

End Function

'示例子过程:

Sub mExample()

    Dim a As Integer, b As Integer

    a = 10: b = 10

    

    Debug.Print "test前: a=" & a & ",b=" & b

    test a, b

    Debug.Print "test后: a=" & a & ",b=" & b

End Sub

示例运行后的结果:

test前: a=10,b=10

test后: a=10,b=20

通过示例,再次理解一下:

ByVal传递的只是值,相当于将变量a的副本传入函数,无论函数中怎样改变a的值,在函数外部,都不会影响变量a原始的值;

ByRef传递的却是引用(即:变量的内存地址,可以理解为变量自身),在函数中对变量b的重新计算、赋值,都会改变实体变量b的值,所以经过函数的洗礼,这个b变量的值已是物是人非,也不再是它的初始值了。



二、ByVal和ByRef进阶



以上的基础不足以满足我们对ByVal和ByRef的好奇心。

1、我们注意到,以上示例向函数中传递的都是变量,所以才存在这种区别。换句话说,ByVal和ByRef只是对变量参数产生影响,如果函数接收的是两个常量值:

test 100, 150

那么使用ByVal、ByRef的结果是一样的,VBA也不会报错。只是这样做会失去函数设置ByRef限定的意义而已。

ByVal参数设计的初衷,是要接收一个变量或一个具体的常量值。而ByRef参数设计的初衷,是要接收一个变量。

2、既然能让ByVal、ByRef发挥作用的是传递变量,那么又要看这个变量属于什么类型。下面对普通变量(如上述示例)、数组变量、对象变量分别说明:

(1)普通变量,最常使用的一种变量,它的变化情况如上述示例。

(2)数组变量,如果函数的参数是一个数组,则必须传递ByRef。

(3)对象变量,同样只能传递ByRef,不能使用ByVal来按值传递,VBA不支持对象按值传递。

3、对于函数中使用的ByRef传递方式,目的可以有两个:一是要使用这个参数值;二是要改变这个参数值。在实际运用中,这两项目的并不是每次都想要达成的。

例如,函数设计中使用了ByRef,但是在使用时偶尔又需要只传递变量的值,而不要改变参数原始的变量值。

一种方法是使用一个第三方变量,其实就是设置一个变量副本,从而间接保护原来的变量:

'示例子过程:

Sub mExample2()

    Dim a As Integer, b As Integer, c As Integer

    a = 10: b = 10: c = b

    

    Debug.Print "test前: a=" & a & ",b=" & b

    test a, c

    Debug.Print "test后: a=" & a & ",b=" & b

End Sub

这个方法看似笨拙,但很有效。

第二种方法是变量作为参数时,使用小括号(看着要高级一些)括起来:

'示例子过程:

Sub mExample3()

    Dim a As Integer, b As Integer

    a = 10: b = 10

    

    Debug.Print "test前: a=" & a & ",b=" & b

    test a, (b)

    Debug.Print "test后: a=" & a & ",b=" & b

End Sub

重点是这个(b),即在传递b变量时,使用小括号括起来,这时就会临时性只传递变量b的值(使其变成了ByVal参数),而不会对原实体变量b造成伤害。

使用小括号的方法,同样适用于数组变量参数。如果要获取函数的返回值,就需要两层括号了,类似这种形式:test(a, (b))。

ByRef总结:如果函数的参数使用了ByRef关键字,就传递一个变量的引用(地址,会改变原变量的值),如果对这个关键字参数只想传递值,可以将变量单独用小括号括起来,这样就只传递变量的值,不会修改变量的原始值,也可以直接使用一个实体的变量副本。



三、ByRef应用技巧



当我们了解了ByVal和ByRef的原理后,在编写VBA代码时,就需要加以注意了。因为参数的限定关键字被省略时,默认是ByRef传递。

通常我们只是使用这个参数传递的值,而不会在函数中对参数进行运算、赋值等动作,所以使用ByVal或ByRef可能感觉不到有什么区别。如果一个函数中传递的变量在该函数运行后,仍需要调用它,就需要注意是否是ByRef传递。

其实,利用ByRef传递,在函数中对传递的变量进行赋值等操作,有时候会收到奇特的效果,如下示例函数(根据身份证号获取生日,同时根据需要获取性别信息):

Function GetBirthDate(ByVal idCard As String, Optional ByRef gender As String) As Date

    Dim birthDate As Date    

    birthDate = DateSerial(CInt(Mid(idCard, 7, 4)), CInt(Mid(idCard, 11, 2)), CInt(Mid(idCard, 13, 2)))

    ' 提取性别

    If Val(Mid(idCard, 17, 1)) Mod 2 = 0 Then

        gender = "女"

    Else

        gender = "男"

    End If    

    GetBirthDate = birthDate

End Function

调用该函数时:

Sub 测试GetBirthDate()

    Dim idCard As String

    Dim gender As String

    

    idCard = "420624199610030080"

    

    '仅获取生日:

    Debug.Print GetBirthDate(idCard)

    

    '获取生日及性别:

    Debug.Print GetBirthDate(idCard, gender)

    Debug.Print gender

    

    '仅获取性别:

    GetBirthDate idCard, gender

    Debug.Print gender

End Sub

不知道你看清这个操作没有,通过将ByRef参数设置一个可选参数,在函数中对该参数赋值。

使用时,如果没有特别的要求,只想得到函数的返回值,就省略该参数,也不会影响函数正常发挥。如果想得到这个经过函数洗礼后的变量的值,就如上述示例中所做,这样,就能够通过一个函数,同时获取到多个返回值的奇特效果。

我们在使用一些API函数时也会遇到这些情形,非常实际的技巧。


阅读原文:原文链接


该文章在 2025/1/24 9:26:18 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2025 ClickSun All Rights Reserved