目录
0.《VBA实用编程技巧》专栏总纲
本文作为专栏《VBA实用编程技巧》专栏其中的一部分,返回专栏总纲,阅读所有文章,点击Link:
在使用VBA编程的时候,我们经常会使用Type函数自定义数据类型。在VBA中,关键字Type用于定义用户自定义的数据类型。这些自定义类型允许你将一组相关的变量组合成一个单独的数据结构,类似于其他编程语言中的结构体或类。使用Type定义的自定义类型可以简化代码并提高可读性。
1.Type类型简介
1.1 VBA中Type类型的好处
VBA中,Type 是一种用户定义的数据类型,它允许您创建自定义的数据结构,以更好地组织和处理数据。使用 Type 定义数据类型具有以下好处,如图1-1:
图1-1 Type定义数据类型的好处
- 数据封装和结构化:
使用 Type,您可以将多个相关的数据项组合成一个单一的复合数据类型。这有助于将数据封装成一个逻辑单元,使代码更易于理解和维护。例如,如果您正在处理员工信息,可以创建一个 EmployeeType 来包含员工的姓名、年龄、职位等属性。 - 提高代码可读性:
通过定义有意义的 Type 名称,您可以使代码更具描述性,从而提高代码的可读性。这有助于其他开发人员理解您的代码意图,并减少错误和误解的可能性。 - 减少代码冗余:
当您在多个地方使用相同的数据结构时,使用 Type 可以避免重复定义相同的变量集。您只需定义一次 Type,然后在代码中多次使用它,从而减少了代码的冗余和复杂性。 - 增强数据验证:
通过定义 Type,您可以为数据结构的每个成员指定数据类型。这有助于在数据赋值时进行隐式的数据类型验证,减少因数据类型不匹配而导致的错误。 - 提高性能:
在某些情况下,使用自定义的 Type 数据类型可能比使用内置的数据类型(如数组或集合)更高效。这是因为自定义类型可以更紧密地匹配您的数据需求,减少不必要的内存占用和处理开销。 - 便于数据传递:
当您需要在函数或过程之间传递多个相关数据项时,使用 Type 可以将它们封装在一个单一的参数中。这使得参数传递更加简洁和高效,同时减少了函数或过程的参数列表的复杂性。
需要注意的是,虽然 Type 在某些情况下非常有用,但它并不是VBA中唯一的数据结构工具。VBA还提供了其他数据结构,如类(Class)和集合(Collection),它们提供了更高级的数据组织和管理功能。在选择使用 Type 还是其他数据结构时,应根据具体的应用场景和需求进行权衡。这些类型后续我们都会进行介绍,请大家持续关注。
1.2 VBA中Type定义类型的方法
如下代码所示,Type类型的使用非常简单,形式如下:
Type 数据类型名
成员1 as 数据类型(VBA内基本数据类型)
成员2 as 数据类型(VBA内基本数据类型)
成员3 as 数据类型(VBA内基本数据类型)
...
end Type
简单举个实例说明一下用法:
Option Explicit
Type student
Name As String
Age As Integer
Score As Single
End Type
Sub TypeTest()
Dim stu01 As student
stu01.Name = "John"
stu01.Age = 20
stu01.Score = 88
Debug.Print "Stu01 Name: " & stu01.Name & vbCrLf & "Age: " & stu01.Age & vbCrLf & "Grade: " & stu01.Score
End Sub
需要注意,Type定义类型只能在标准模块或类模块中定义,不能在对象模块(比如工作表)中创建。
2.VBA中Type类型存入字典的方法
在VBA中,如果我们直接把一个Type类型存入字典,会发现是无法实现的。如下代码,我们定义一个学生信息的数据类型,然后尝试存入字典:
Option Explicit
Option Base 0
Type student
Name As String '姓名
Age As Integer '年龄
Score As Single '分数
End Type
Sub TypeData2Dic()
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary") '创建字典
Dim i As Integer
Dim student() As student '创建studen类数据
'定义一个student数组
ReDim student(1)
student(0).Name = "Jim"
student(0).Age = 10
student(0).Score = 98.5
student(1).Name = "Joy"
student(1).Age = 11
student(1).Score = 88
'存入字典
For i = LBound(student) To UBound(student) Step 1
If Not dict.Exists(student(i).Name) Then
dict.Add student(i).Name, student(i)
End If
Next i
End Sub
如果按上述代码运行,会爆出如下图2-1所示的编译错误提示,这是因为在VBA中的字典只能存入VBA定义的基本类型,如string,integer等,无法对用户定义的type结构体类型进行存储。
图2-1.编译错误
那么如何解决这个问题呢,我在日常的使用中通常使用如下这2个方法,如果大家还有更好的方法,可以一起分享一下。
2.1 字典存储Type类型数据数组的序号进行变相引用
代码修改如下:
Option Explicit
Option Base 0
Type student
Name As String '姓名
Age As Integer '年龄
Score As Single '分数
End Type
Sub TypeData2Dic()
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary") '创建字典
Dim i As Integer
Dim student() As student '创建studen类数据
'定义一个student数组
ReDim student(1)
student(0).Name = "Jim"
student(0).Age = 10
student(0).Score = 98.5
student(1).Name = "Joy"
student(1).Age = 11
student(1).Score = 88
'存入字典
For i = LBound(student) To UBound(student) Step 1
If Not dict.Exists(student(i).Name) Then
dict.Add student(i).Name, i '存储的是数组的序号,不再是Type类型数据
End If
Next i
'下面测试一下
Debug.Print student(dict("Joy")).Score '查看姓名为Joy同学的得分
'实测运行结果为:88
End Sub
如上代码,字典存储的是student数组的序号,字典的键是学生的姓名,这样就可以直接通过student(dic("学生姓名"))查询相关信息了。
2.2 通过类模块创建字典
VBA里我们可以创建一个类模块,类模块可以看成是一个对象,是可以存入字典的。首先VBA创建一个类模型,命名为student,并在类模块里定义上面程序的学生信息。如下图2。
图2-2.类模块的创建方式示意图
然后在模块1中添加主程序,代码如下:
Option Explicit
Option Base 0
Sub TypeData2Dic()
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary") '创建字典
Dim i As Integer
Dim student() As New student '创建studen类数据
'定义一个student数组
ReDim student(1)
student(0).Name = "Jim"
student(0).Age = 10
student(0).Score = 98.5
student(1).Name = "Joy"
student(1).Age = 11
student(1).Score = 88
'存入字典
For i = LBound(student) To UBound(student) Step 1
If Not dict.Exists(student(i).Name) Then
dict.Add student(i).Name, student(i) '将类模块对象存入字典
End If
Next i
'下面测试一下
Debug.Print dict("Joy").Score '查看姓名为Joy同学的得分
'实测运行结果为:88
End Sub
上面就是我经常使用的两种方法,欢迎指正和补充。