从前文我们可以看出,过程是用来完成一件事情,事情的结果可能对调用方没有影响(譬如使用传值参数),也可能会对调用方造成影响(譬如使用传地址参数并且在过程中修改参数),但过程本身并不返回什么给调用方。函数不同,函数的目的就是返回值给调用方:调用方传递参数给函数,函数经过内部处理后,将结果返回给调用方。VBA 的数学库提供了很多数学函数,譬如取绝对值的函数 Abs(),譬如计算平方根的函数 Sqr(),譬如正弦函数 Sin() 等。Dim x As DoubleDim y As Doublex = -3.5y = Abs(x)Debug.Print y ' 3.5y = Sqr(x) ' ERROR!
因为负数的平方根没有意义,因此,上面例子中的 y = Sqr(x) 语句发生运行时错误:无效的过程调用或参数(Invalid procedure call or argument)。之所以发生这个错误,是因为我们传递给函数 Sqr 的实参(argument)是不合法的(invalid),或者说,无效的。注意:VBA 将 Sub 和 Function 统一称为“过程”(procedure),所以,上面的英文信息,Invalid procedure call or argument,对于 Sub 和 Function 都适用。这给我们的行文造成了一定的困扰,因为我们为了区别 Sub 和 Function,称 Sub 为过程,Function 为函数。为了避免混淆 Sub 过程和 procedure 过程,以后我们直接称 Sub 为 Sub,不再称中文“过程”,而将“过程”这个词留给 procedure。例2. 将 Sub ComputeCircleArea 改写成 Function CalcCircleAreaFunction CalcCircleArea(ByVal radius AsDouble) AsDouble If radius <0Then CalcCircleArea =-1Else CalcCircleArea = WorksheetFunction.Pi() * radius * radiusEnd IfEndFunction
在过程版本的 ComputeCircleArea 中,我们检查参数,如果不合法,则直接退出过程。在过程中这样做是可以的,但在函数中不可以。因为函数是要返回值给调用方,如果直接退出函数,则函数仍然会返回值给调用方,但具体返回什么值我们不知道,也有可能返回合法的值,这当然不是我们函数的正常逻辑。因此,我们要控制返回的值。如果参数不合法,一种选择是返回负数值。因为圆面积不可能为负数,这也就相当于告诉调用方:传递过来的参数有错误,无法计算。第二种选择是抛出错误,这个留待以后讨论错误处理时再讲。如果参数合法(甚至为 0),就可以按照圆面积的计算公式计算面积,并返回计算结果。注意:函数返回值是通过将返回值赋给函数名称实现的。- 函数的参数传递和过程是一样的,都分为传值和传地址两种方式。
- 过程不返回值,因此可以什么也不做直接返回,但函数需要返回值,因此要小心处理。
[ modifier ] Function FuncName([ parameters ]) [ As Type ][ FuncName = expression ][ FuncName = expression ]由此可见,所谓函数就是一个 Function ... End Function 的结构,这个结构返回一个值,这个值具有某种类型。因此定义函数时要声明函数的类型。所谓函数的类型,实际上是函数返回值的类型,由 As Type 声明(Type 为具体的类型)。如果没有 As Type 声明,则返回变体类型 Variant。函数返回值类型(以后简称函数类型) Type 可以是:Byte, Boolean, Integer, Long, Currency, Single, Double, Date, String, Object, Variant, 以及任何的用户定义类型 UDT。注意:函数类型 String 是指变长字符串类型,函数类型不能是形如 String * n 的定长字符串类型。在这个例子中,我们利用 VBA 函数返回值类型的灵活性,来实现一种不同的错误处理。函数 CalcCircleArea 不声明具体的类型,因此其类型将是变体类型 Variant。因为是变体类型,就可以返回不同的类型。利用这一特点,我们在检测到参数不合法时,返回字符串形式的错误信息。而对于合法的参数,则返回 Double 类型的值。注:上面例子中的 CalcCircleArea 函数也可以声明其类型为 Variant,如下:Function CalcCircleArea(ByVal radius AsDouble) As Variant...EndFunction
在函数 CalcCircleArea 的调用方,我们判断函数的返回类型,如果是字符串类型(VarType 函数返回 5 表示子类型是 String 的变体类型),则说明有错,否则表示函数返回正常计算结果。在这种错误处理方式中,我们根据返回的错误信息就可以精确地知道具体的错误及原因,有利于快速定位及修正错误。