本文系因违规而删除的2017年10月31日推送文章经修改后重新推送,已看过的朋友可直接飘过,免得浪费时间。
在VBA中,可以使用数组作为过程的参数,也可以从函数过程返回数组,这是一项很有用的技术。
使用数组作为过程的参数
可以传递数组作为过程的参数,如下面的示例代码:
Sub test()
Dim myArray(2) As Long
Dim iCount As Integer
Dim str As String
myArray(0) = 1
myArray(1) = 2
myArray(2) = 3
testPassArray passArray:=myArray
For iCount = LBound(myArray) ToUBound(myArray)
str = str & 'myArray('& iCount & ') = ' & myArray(iCount) & vbCr
Next iCount
MsgBox str
End Sub
SubtestPassArray(ByRef passArray() As Long)
Dim i As Long
For i = LBound(passArray) ToUBound(passArray)
passArray(i) = (i 1) * 100
Next i
End Sub
在代码中:
将数组myArray传递到被调用的testPassArray过程,在该过程中,数组经过处理后,最后的结果如图1所示。
注意到testPassArray过程名后的关键字ByRef,表明数组是通过引用传递的,这样,在被调用过程中对数组的修改都是对实际所传递的数组的修改,从图1所示的结果中我们也可以看出来。
在调用过程中的数组的数据类型与被调用过程中传递给的参数中的数组的数据类型要相匹配,如本例中的数组myArray和passArray都是Long型。不能简单地将被调用过程的参数声明为Variant型,想当然地认为可以接受任意类型的数组。
下面演示传递动态数组给被调用函数的示例代码:
SubtestDynamicArray()
Dim DynArray() As Double
Dim iCount As Long
Dim str As String
'调用PopulateArray过程来调整数组大小并填充相应的数据
PopulateArray myArray:=DynArray,testRange:=Range('A2:A9'), strName:='张三'
str = '张三的测试成绩分别为: '
For iCount = LBound(DynArray) ToUBound(DynArray)
str = str & vbCr &DynArray(iCount)
Next iCount
MsgBox str
End Sub
SubPopulateArray(ByRef myArray() As Double, testRange As Range, strName As String)
Dim rng As Range
Dim iIndex As Long
If testRange Is Nothing Then
MsgBox '单元格区域为空!'
Exit Sub
End If
'重新定义动态数组的大小为整个单元格区域的单元格数
ReDim myArray(1 To testRange.Cells.Count)
'遍历单元格区域,找到相应的单元格后将对应值存储到数组中
For Each rng In testRange.Cells
If rng.Value = strName Then
iIndex = iIndex 1
myArray(iIndex) = rng.Offset(0,1).Value
End If
Next rng
'重新定义数组大小为已填充的元素数
ReDim Preserve myArray(1 To iIndex)
End Sub
在代码中:
在主调过程testDynamicArray中声明了动态数组DynArray(),并将其传递给被调过程PopulateArray。在被调过程PopulateArray中,根据实际需要调整大小。
注意到,在被调过程PopulateArray中,我们首先将数组大小调整为可能的最大值,待填充完数据后,再将其调整为实际大小。这样,避免了每次增加数据时都要重新调整数组大小而导致会发生的可能问题。
注意,在被调用过程的参数列表中声明数组时,不能包括大小。
上述代码运行的结果如图2所示。
下面的示例传递固定大小的静态数组到Function过程:
SubtestPassArrayToFunction()
Dim myArray(1 To 3) As Long
Dim lngResult As Long
myArray(1) = 10
myArray(2) = 20
myArray(3) = 30
result = SumToArray(passArray:=myArray)
MsgBox result
End Sub
FunctionSumToArray(passArray() As Long) As Long
Dim iCount As Integer
Dim lngTotal As Long
For iCount = LBound(passArray) ToUBound(passArray)
lngTotal = lngTotal passArray(iCount)
Next iCount
SumToArray = lngTotal
End Function
在代码中:
主过程testPassArrayToFunction调用SumToArray过程并传递需要求和的数组,SumToArray过程对接收到的数组求和并返回结果。
前面我们讲过,在调用过程中的数组的数据类型与被调用过程中传递给的参数中的数组的数据类型要相匹配。然而,有时可能不知道传递的数组的类型,那该如何做呢?
如果要传递任意类型的数组,那么在被调用过程的参数声明中不要将要接收数组的参数声明为数组,而应该声明为Variant型。例如,将上述Function过程修改如下,使其可以接收其他类型的数组数据。
FunctionSumToArray1(passArray As Variant)
Dim iCount As Integer
Dim lngTotal As Long
If IsArray(passArray) Then
ForiCount = LBound(passArray) To UBound(passArray)
lngTotal = lngTotal passArray(iCount)
Next iCount
End If
SumToArray = lngTotal
End Function
从函数返回数组
下面的示例演示从函数返回一个数组:
SubtestReturnArray()
Dim myArray() As Long
Dim iCount As Long
myArray = LoadNumbers(Low:=21, High:=30)
For iCount = LBound(myArray) To UBound(myArray)
Debug.Print myArray(iCount)
Next
End Sub
FunctionLoadNumbers(Low As Long, High As Long) As Long()
Dim resultArray() As Long
Dim lngIndex As Long
Dim lngVal As Long
If Low > High Then
Exit Function
End If
ReDim resultArray(1 To (High - Low 1))
lngVal = Low
For lngIndex = LBound(resultArray) ToUBound(resultArray)
resultArray(lngIndex) = lngVal
lngVal = lngVal 1
Next lngIndex
LoadNumbers = resultArray()
End Function
在代码中:
接收数组结果的变量(如示例中的myArray())必须是动态数组,并且必须与返回的数组有相同的数据类型(如示例中的Long型),或者声明为Variant变量(例如,Dim myArray As Variant)。
如果接收数组结果的变量(如示例中的myArray())是静态数组,那么函数返回值的数组必须是动态数组,它将自动调整大小来返回合适的数组。
如果接收数组与返回的数组的下标索引的基准值不同,那么将使用返回的数组的下标索引基准值。
将一个数组赋值给另一个数组
VBA不允许将一个数组直接赋给另一个数组,即便其大小和数据类型都一致。例如,下面的代码:
Dim A(1 To 10) AsLong
Dim B(1 To 10) AsLong
A = B
运行代码后将产生编译错误:不能给数组赋值。
然而,可以将包含数组的Variant型变量赋值给另一个Variant型变量,例如下面的代码:
Dim A As Variant
Dim B As Variant
Dim i As Long
A = Array(11, 22,33)
B = A
通常情况下,想要将一个数组的内容转移到另一个数组中,就必须遍历数组并逐元素赋值:
Dim A(1 To 3) AsLong
Dim B(0 To 5) AsLong
Dim lngIndexA AsLong
Dim lngIndexB AsLong
A(1) = 11
A(2) = 22
A(3) = 33
lngIndexB =LBound(B)
For lngIndexA =LBound(A) To UBound(A)
If lngIndexB <= UBound(B) Then
B(lngIndexB) = A(lngIndexA)
Else
Exit For
End If
lngIndexB = lngIndexB 1
Next lngIndexA
注意到,上面代码中数组A与B的维数不同,数组B的维数大于数组A的维数。如果数组A的维数大于数组B的维数,则当数组B的UBound达到时循环终止。
相关链接:
VBA进阶 | 数组基础01: 用最浅显的介绍来帮助你认识数组
VBA进阶 | 数组基础06: 与数组相关的函数——Array函数与IsArray函数
VBA进阶 | 数组基础07: 与数组相关的函数——Split函数与Join函数
VBA进阶 | 数组基础08: 与数组相关的函数——Filter函数
本文整理自cpearson.com,转载请注明出处。
欢迎在下面留言,完善本文内容,让更多的人学到更完美的知识。
联系客服