Excel精英培训网

 找回密码
 注册
数据透视表40+个常用小技巧,让你一次学会!
查看: 4879|回复: 1

[分享] 心得:参数传递数组、函数返回数组的程序中常见错误

[复制链接]
发表于 2016-1-25 16:52 | 显示全部楼层 |阅读模式
本帖最后由 uhnmki 于 2016-2-18 15:51 编辑

VBA中参数或函数值使用数组,也就是说:
一、把数组赋给参数,传递到函数Function/过程Sub中。(个人简称参传数组、或数组传参
二、把数组赋给函数Function返回值,让函数返回的是数组。(个人简称:函返数组、或数组返函
两种使用情形下经常出现错误,这其实和数组定义之后的重定义,以及数组赋值有关。以下用几个麻雀式小例,对错误归纳梳理。

一、数组作参数,传递给函数
根源:主过程中对数组的声明和被调用函数/过程中对该参数(数组)的声明不一致。
现象:报编译错误。此时主过程中引用函数传递数组参数的地方会被光标选中以提示。
错误:
1) 在函数/过程中对要传递数组的参数用 Dim 作了声明,这是个会引起错误的“严谨”。
Sub Main()
   Dim myShuZu()    '主过程声明数组
   Func myShuZu     '引用函数Func,传递数组参数myShuZu
End Sub
Function Func(ShuZu)
   Dim ShuZu()   '(x)“编译错误:当前范围内的声明重复”
   ReDim ShuZu(4 To 6, 5 To 8)     '如果特想归拢那个数组参数的话,可以用 ReDim 达成心愿。
   Debug.Print UBound(ShuZu)
End Function

主过程已经 Dim 声明过一次 myShuZu 变量,在函数内部又 Dim 声明参数是数组,由此造成重复声明数组的错误。
解决:在函数/过程内部,不要用 Dim 声明参数是数组,如果想调整参数数组,只能用 ReDim。

2) 主过程中设定的数组数据类型和函数/过程中设定的不一致。
Sub Main()
   Dim myShuZu()    '默认数组的数据类型为 Variant。
   ReDim myShuZu(2 To 4, 3 To 5)
   Func myShuZu
End Sub
Function Func(ShuZu)
   ReDim ShuZu(3 To 7, 4 To 9) As Integer    '(x)运行时错误13:类型不匹配。
   Debug.Print UBound(ShuZu)
End Function

上例如果反过来,主过程规定数组数据类型为整型 Dim myShuZu() As Integer,而函数/过程内部规定为可变型 ReDim ShuZu(3 To 7, 4 To 9) As Variant,也报同样的错误。
解决:在主过程和函数内部对数组参数的数据类型的规定要完全一致。

3) 在函数头部的参数声明,和主过程中声明的不一致。
Sub Main()
   Dim myShuZu() As Integer
   ReDim myShuZu(2 To 4, 3 To 5)
   Func myShuZu
End Sub
'①(x)Function Func(ShuZu As Integer)    '报:“编译错误:ByRef 参数类型不符”。
'Function Func(ShuZu() As Integer)    '正确的写法。※ShuZu 没带"()"时是整型数,而非数组。
'②(x)Function Func(ShuZu() As Variant)    '报:“编译错误:类型不匹配”
'③(x)Function Func(ShuZu())    '报:“编译错误:类型不匹配: 缺少数组或用户定义类型”
'Function Func(ShuZu As Variant)    '可以。这是把参数设成可变型数据--也就是默认的类型。
Function Func(ShuZu)    '通过。默认参数类型为 Variant。
   ReDim ShuZu(3 To 7, 4 To 9)
   Debug.Print UBound(ShuZu)
End Function

上例中,如果主过程先声明一个Variant,然后转成数组,再传给函数参数的话,那么该参数在函数头部指定时也得是Variant,不能是数组,否则也将出现③所报的错误。
解决:要么修改主过程中 Dim(注意,和ReDim无关)的数组型变量声明,
   要么修改函数/过程中头部的参数声明,使两者在数据类型、维数、元素数目等处严格一致;
   或者干脆就令函数/过程中的参数为 Variant,这样它可以接受任意数组。还省事了。


【总结】:主、函声明一致,或者函参 Variant。

两个思路:
1) 函数/过程可以接受任意数组,然后再在内部调整数组的类型,
2) 传递规整好了的数组,给函数/过程处理。

前者参数匹配较宽松,因此函数/过程内部不得不对传入的数组先进行分辨、规整等工作,这样函数/过程冗长庞杂,不过一旦打包好了,函数有兼容性,主过程倒可以省事。

后者对参数匹配要求严,主过程必须提供精饲料(严格匹配的数组),喂给函数,不过呢,函数可以短小精干。

前者的函数/过程,接受数组的参数,最好指定为Variant(或者就默认得了),后者在主程序中要严格按照在函数中指定参数的数组样式。

二、函数返回数组
根源:主过程接受函数的那个(数组)变量的声明,与函数头部的声明不一致。
现象:在主过程中引用函数/过程的地方出现编译错误,或者在函数内部给函数赋值的地方出现运行时错误。
错误:
1) 函数头部声明加了 As Integer 之类的函数数据类型声明。
Sub Main()
   Dim myShuZu()
   ReDim myShuZu(2 To 4, 3 To 5)
   Debug.Print UB(Func(myShuZu))
End Sub
Function Func(ShuZu) As Integer    '一旦指定数据类型,就意味着函数是该类型单值,而不是数组。
   ReDim ShuZu(3 To 7, 4 To 9)
   Func = ShuZu    '(x)。报运行时错误 '13': 类型不匹配
End Function

除非函数后加 As Variant,否则加什么数据类型都是错,这一点和前面一、1)中说的函数/过程内加Dim的情况类似,画蛇添足装严谨,反累为犬。
解决:在函数头部,不要加函数的数据类型(除 Variant 外)。其实什么都不加,默认 Variant 反倒最好。

2) 主过程中数组型变量与函数返回的数组类型不同。
Sub Main()
   Dim myShuZu As Integer
   Dim Result()    '默认Variant。要么改这里的定义为 As Integer,与函数返回的数组一致。
   Dim UB%
   ReDim myShuZu(2 To 4, 3 To 5)
   Result = Func(myShuZu)    '(x)报:运行时错误'13': 类型不匹配。
   UB = UBound(Result)
   Debug.Print UB(Func(myShuZu))
End Sub
Function Func(ShuZu)    '默认函数值属 Variant 类型变量
   ReDim ShuZu(3 To 7, 4 To 9)    'ReDim 是不能改数组的数据类型的,要改类型见后面。
   Func = ShuZu    '直接赋值,函数值的数组类型是 Integer。要改类型,只能象下面那样操作:
'   Dim tmp(3 To 7, 4 To 9)     '新建一个转存用的数组变量(Variant),类型与主过程的 Result() 一致。
'   For i = 3 To 7    '俩数组元素对元素,一个一个地,循环赋值
'      For j = 4 To 9
'         tmp(i, j) = ShuZu(i, j)
'      Next
'   Next
'   Func = tmp
    '用转类型后的媒介变量给函数赋值
End Function

上例出错的原因就是函数Func返回的数组数据类型是 Integer,而 Result 数组变量是默认的 Variant,两者不一致。注意,数组变量给数组变量赋值,不仅要考虑维数、元素数等限制,数据类型也要考虑,即使元素为Variant的数组也不可以被元素为Integer的数组赋值,这是数组变量和单值变量在赋值时很不一样的地方。所以,要么在函数/过程的内部改要返回的数组类型,要么在主过程中改Result类型和函数返回数组一致(As Integer)。其实,在主过程中定义数组变量时,“什么也不作”,把 Result 默认为 Variant,反倒能够接受函数返回来的任何类型数组,当然,如果执意要得到特定类型的数组,之后还得转存(另设一个数组变量,元素对元素,循环逐一赋值),这相当于不在函数/过程内作转存,而是放到主过程里作。
解决:要么在函数/过程内部改返回的数组类型,要么在主过程中改(接受函数值的)数组变量的定义

需要指出的是,并不是因为函数/过程有不同于普通情况的性质,才造成出错,其实,在无调用的情况下,数组变量间赋值,类型必须一致--这是个铁的法则,否则呈现的错误和上面类似。对于用数组给参数和函数返回值赋值,只不过象小学数学题一样,拐个弯表达而已。

这个问题经常不引人注意,就我浏览论坛看到的错误,十有八九,都是这种事,而有时 VBA 报告的错误,常令人摸不着头脑,此前没人总结:看到什么样的报错,可能对应的是什么原因。本文填补了这方面的空白……

运行系统:WinXP SP2/SP3 + OfficeXP/2003

小学填数字游戏题.ZIP (22.94 KB, 下载次数: 6)
excel精英培训的微信平台,每天都会发送excel学习教程和资料。扫一扫明天就可以收到新教程
发表于 2016-1-25 21:06 | 显示全部楼层
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|Excel精英培训 ( 豫ICP备11015029号 )

GMT+8, 2024-5-29 10:50 , Processed in 0.205701 second(s), 9 queries , Gzip On, Yac On.

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表