数组 (Visual Basic)

“数组”是一组逻辑上相互关联的值,例如初级学校每个年级的学生数。

数组允许您通过同一名称来引用这些相关的值,并使用一个称为“索引”或“下标” 的数字来区分这些值。 每个值称为数组的“元素”。 这些值是连续的,从索引 0 一直到最大索引值。

与数组相反,包含单个值的变量称为“标量”变量。

示例

下面的示例声明一个数组变量来存储初级学校每个年级的学生数。

Dim students(6) As Integer

前面的示例中的数组 students 包含 7 个元素。 元素的索引范围为从 0 到 6。 此数组比声明 7 个不同的变量更简单。

下图显示了数组 students。 对于数组的每个元素:

  • 元素索引表示年级(索引 0 表示幼儿园)。

  • 包含在元素中的值表示该年级的学生数。

"students" 数组的元素

图:显示学生数的数组

下面的示例显示了如何引用 students 数组的第一个、第二个和最后一个元素。

Dim kindergarten As Integer = students(0)
Dim firstGrade As Integer = students(1)
Dim sixthGrade As Integer = students(6)
MsgBox("Students in kindergarten = " & CStr(kindergarten))
MsgBox("Students in first grade = " & CStr(firstGrade))
MsgBox("Students in sixth grade = " & CStr(sixthGrade))

可以只通过使用数组变量名(没有索引),将数组作为一个整体引用。

数组维数

前面示例中的数组 students 使用一个索引,因此称为“一维”。 使用多个索引或下标的数组称为“多维”。 有关更多信息,请参见 Visual Basic 中的数组维数

另一种数组是将其他数组作为元素存储的数组。 这称为“数组的数组”或“交错数组”。 交错数组可以是一维或多维,它的元素也可以是一维或多维。 有时,应用程序中的数据结构是两维的但不是矩形。 例如,一个月份的数组,其每个元素又是天数的数组。 由于不同的月份有不同的天数,元素不能构成一个矩形的两维数组。 在这种情况下,可以使用交错数组而不是多维数组。

声明数组

使用 Dim 语句声明数组变量的方法与声明任何其他变量的方法一样。 在变量名后面加上一对或多对圆括号,即指示该变量将存储数组而不是“标量”(包含单个值的变量)。

若要声明一维数组变量,请在变量名后面添加一对圆括号。

Dim cargoWeights() As Double

若要声明多维数组变量,请在变量名后面添加一对圆括号,圆括号内的各维度之间用逗号分隔。

Dim atmospherePressures(,,,) As Short

若要声明交错数组变量,请在变量名后面添加与嵌套数组级数相同的圆括号对。

Dim inquiriesByYearMonthDay()()() As Byte

前面的示例只声明了数组变量,但没有为它们分配数组。 您仍必须创建数组,对该数组进行初始化,并将它分配给变量。

零长度数组

不含任何元素的数组也称为“零长度数组”。 存储零长度数组的变量不具有 Nothing 值。 若要创建没有元素的数组,请将数组的其中一个维度声明为 -1,如下面的示例所示。

Dim twoDimensionalStrings(-1, 3) As String

下列情况下可能需要创建一个零长度数组:

  • 您的代码需要访问 Array 类的成员(例如 LengthRank)或调用像 UBound 这样的 Visual Basic 函数,但不希望出现 NullReferenceException 异常。

  • 您希望简化代码,不必将 Nothing 作为特例进行检查。

  • 您的代码与某个应用程序编程接口 (API) 进行交互,该接口要求您向一个或多个过程传递零长度数组,或者从一个或多个过程返回零长度数组。

创建数组

创建数组有两种方法。 可以在声明数组时提供其大小,或者因为数组是对象,所以可以使用 New 运算符 (Visual Basic) 子句创建它并将它分配给数组变量。 此操作可作为数组声明的一部分或在后续赋值语句中执行,如下面的示例所示。

cargoWeights = New Double() {}
atmospherePressures = New Short(,,,) {}
inquiriesByYearMonthDay = New Byte()()() {}

在执行这些语句后,数组长度为 0。

提示

New 子句必须指定类型名称,其后跟圆括号、再跟大括号 ({})。 圆括号不表示对数组构造函数的调用, 而是表示对象类型为数组类型。 可以在大括号内提供初始化值。 编译器需要大括号,即使您没有为其提供任何值。 因此,New 子句必须包括圆括号和大括号,即使它们都不包含值。 如果不包括大括号,则编译器假定您要调用指定类型的构造函数。

可以使用几种不同的方法来定义数组大小。 可以在声明数组时提供大小,如下面的示例所示。

Dim cargoWeights(10) As Double
Dim atmospherePressures(2, 2, 4, 10) As Short
Dim inquiriesByYearMonthDay(20)()() As Byte

也可以在创建数组时使用 New 子句提供其大小,如下面的示例所示。

cargoWeights = New Double(10) {}
atmospherePressures = New Short(2, 2, 4, 10) {}
inquiriesByYearMonthDay = New Byte(20)()() {}

如果具有现有的数组,则可以使用 Redim 语句重新定义其大小。 可以指定 Redim 语句保留当前存储在数组中的值,也可以指定它创建新的空数组。 下面的示例演示使用 Redim 语句修改现有数组的大小的不同方式。

' Assign a new array size and retain the current element values.
ReDim Preserve cargoWeights(20)
' Assign a new array size and retain only the first five element values.
ReDim Preserve cargoWeights(4)
' Assign a new array size and discard all current element values.
ReDim cargoWeights(15)

有关更多信息,请参见 ReDim 语句 (Visual Basic)

用初始值填充数组

可以使用数组文本创建包含一组初始值的数组。 数组文本由括在大括号 ({}) 内的一组逗号分隔值组成。

使用数组文本创建数组时,可以提供数组类型或使用类型推理确定数组类型。 下面的代码演示了这两个选项。

Dim numbers = New Integer() {1, 2, 4, 8}
Dim doubles = {1.5, 2, 9.9, 18}

使用类型推理时,数组的类型由为数组文本提供的值列表中的主导类型确定。 “主导类型”是数组文本中所有其他类型都可以扩大到的唯一类型。 如果无法确定此唯一类型,则主导类型是数组中所有其他类型都可以收缩到的唯一类型。 如果这两种唯一类型都无法确定,则主导类型是 Object。 例如,如果为数组文本提供的值列表包含 Integer、Long 和 Double 类型的值,则得到的数组属于 Double 类型。 Integer 和 Long 都扩大到 Double 且仅扩大到 Double。 因此,Double 是主导类型。 有关更多信息,请参见扩大转换和收缩转换 (Visual Basic)。 这些推理规则适用于为数组(在类成员中定义的局部变量)推断的类型。 虽然在创建类级变量时可以使用数组文本,但是不能在类级使用类型推理。 因此,在类级指定的数组文本将为数组文本提供的值推断为类型 Object。

在使用数组文本创建的数组中,可以显式指定元素的类型。 在这种情况下,数组文本中的值必须扩大到数组的元素类型。 下面的代码示例从整数列表创建一个 Double 类型的数组。

Dim values As Double() = {1, 2, 3, 4, 5, 6}

嵌套的数组文本

使用嵌套的数组文本,可以创建多维数组。 嵌套的数组文本必须具有与所得数组一致的维度和维数(或“秩”)。 下面的代码示例使用数组文本创建一个二维整数数组。

Dim grid = {{1, 2}, {3, 4}}

在前面的示例中,如果嵌套的数组文本中的元素数不匹配,则会出现错误。 如果将数组变量显式声明为非二维,则也会出现错误。

提示

通过将内部数组文本括在圆括号内,可以在提供不同维度的数组文本时避免错误。 圆括号强制计算数组文本表达式,并将结果值用于外部数组文本。 下面的代码对此进行演示。

Dim values = {({1, 2}), ({3, 4, 5})}

使用嵌套的数组文本创建多维数组时,可以使用类型推理。 使用类型推理时,推断出的类型是某嵌套级别的所有数组文本中所有值的主导类型。 下面的代码示例从 Integer 和 Double 类型的值创建一个 Double 类型的二维数组。

Dim a = {{1, 2.0}, {3, 4}, {5, 6}, {7, 8}}

有关其他示例,请参见如何:在 Visual Basic 中初始化数组变量

在数组中存储值

使用 Integer 类型的索引,可以访问数组中的每个位置。 通过使用括在圆括号内的索引来引用每个数组位置,可以在数组中存储和检索值。 多维数组的索引由逗号 (,) 分隔。每个数组维度都需要一个索引。 下面的示例是一些在数组中存储值的语句。

Dim i = 4
Dim j = 2

Dim numbers(10) As Integer
Dim matrix(5, 5) As Double

numbers(i + 1) = 0
matrix(3, j * 2) = j

下面的示例演示了一些从数组中获取值的语句。

Dim v = 2
Dim i = 1
Dim j = 1
Dim k = 1
Dim wTotal As Double = 0.0
Dim sortedValues(5), rawValues(5), estimates(2, 2, 2) As Double
Dim lowestValue = sortedValues(0)
wTotal += (rawValues(v) ^ 2)
Dim firstGuess = estimates(i, j, k)

对于数组的每一维,GetUpperBound 方法都返回索引可具有的最大值。 最小索引值始终为 0。

数组大小

数组的大小是数组的所有维度的长度乘积。 它表示数组中当前包含的元素的总数。

下面的示例声明一个三维数组:

Dim prices(3, 4, 5) As Long

变量 prices 中数组的总大小是 (3 + 1) x (4 + 1) x (5 + 1) = 120。

使用 Length 属性,可以查找数组的大小。 使用 GetLength 方法,可以查找多维数组中每个维度的长度。

通过为数组变量分配新的数组对象,或者通过使用 ReDim 语句,可以调整数组变量的大小。

处理数组大小时有几件事情需要注意。

维度长度

每个维度的索引从 0 开始,这意味着索引范围为从 0 到它的上限。 因此,给定维度的长度比该维度的声明上限大 1。

长度限制

数组的每个维度的长度最大为 Integer 数据类型的最大值 (2 ^ 31) - 1。 但是,数组的总大小还受系统可用内存的限制。 如果您尝试初始化超出可用 RAM 量的数组,公共语言运行时将引发 OutOfMemoryException 异常。

大小和元素大小

数组的大小与它的元素的数据类型无关。 大小始终表示元素的总数,而不是元素所占用的存储字节数。

内存消耗

对数组在内存中的存储方式做任何假定都是不安全的。 不同数据宽度的平台上的存储各不相同,因此同一个数组在 64 位系统中占用的内存比在 32 位系统中多。 根据初始化数组时系统配置的不同,公共语言运行时 (CLR) 可以分配存储来尽可能紧密地压缩元素,或者在自然的硬件边界上完全对齐元素。 另外,数组的控制信息也需要存储开销,而这类开销会随每个增加的维度而增加。

数组类型和其他类型

数据类型

每个数组都具有数据类型,但与其元素的数据类型不同。 没有一种可用于所有数组的数据类型。 相反,数组的数据类型由数组的维数(或“秩”)和数组中元素的数据类型确定。 只有在两个数组变量具有相同的秩并且它们的元素具有相同的数据类型时,才能将它们看成属于同一数据类型。 数组中维度的长度不会影响数组数据类型。

每个数组从 System.Array 类继承,您可以将变量声明为 Array 类型,但不能创建 Array 类型的数组。 此外,ReDim 语句 (Visual Basic) 不能处理声明为 Array 类型的变量。 由于这些原因以及类型安全考虑,建议将每个数组声明为特定的类型,例如前面示例中的 Integer。

可以通过几种方法确定数组或其元素的数据类型。

  • 可以对变量调用 Object.GetType 方法,从而得到包含该变量的运行时类型的 Type 对象。 Type 对象在其属性和方法中保存了大量信息。

  • 可以将变量传递给 TypeName 函数,从而得到包含运行时类型的名称的 String。

  • 可以将变量传递给 VarType 函数,从而得到表示变量的类型分类的 VariantType 值。

下面的示例调用 TypeName 函数来确定数组的类型和数组中元素的类型。 数组类型是 Integer(,),而数组中元素的类型是 Integer。

Dim thisTwoDimArray(,) As Integer = New Integer(9, 9) {}
MsgBox("Type of thisTwoDimArray is " & TypeName(thisTwoDimArray))
MsgBox("Type of thisTwoDimArray(0, 0) is " & TypeName(thisTwoDimArray(0, 0)))

使用集合替代数组

尽管集合一般是用来处理 Object 数据类型 的,但它也可以用来处理任何数据类型。 有时用集合存取数据比用数组更加有效。

如果需要更改数组的大小,必须使用 ReDim 语句 (Visual Basic)。 当您这样做时,Visual Basic 会创建一个新数组并释放以前的数组以便处置。 这需要一定的执行时间。 因此,如果您处理的项数经常更改,或者您无法预测所需的最大项数,则可以使用集合来获得更好的性能。

集合不用创建新对象或复制现有元素,它在处理大小调整时所用的执行时间比数组少,而数组必须使用 ReDim。 但是,如果不更改或很少更改大小,数组很可能更有效。 一直以来,性能在很大程度上都依赖于个别的应用程序。 您应该花时间把数组和集合都尝试一下。

专用集合

.NET Framework 还提供了各种用于常规集合和特殊集合的类、接口和结构。 System.CollectionsSystem.Collections.Specialized 命名空间包含定义和实现,定义和实现又包括字典、列表、队列和堆栈。 System.Collections.Generic 命名空间提供其中许多泛型版本,它们又具有一个或多个类型参数。

如果集合中只包含具有一种特定数据类型的元素,泛型集合在强制“类型安全”方面具有优势。 有关泛型的更多信息,请参见 Visual Basic 中的泛型类型 (Visual Basic)

专用集合

.NET Framework 还提供了各种用于常规集合和特殊集合的类、接口和结构。 System.CollectionsSystem.Collections.Specialized 命名空间包含定义和实现,定义和实现又包括字典、列表、队列和堆栈。 System.Collections.Generic 命名空间提供其中许多泛型版本,它们又具有一个或多个类型参数。

如果集合中只包含具有一种特定数据类型的元素,泛型集合在强制“类型安全”方面具有优势。 有关泛型的更多信息,请参见 Visual Basic 中的泛型类型 (Visual Basic)

示例

下面的示例使用 .NET Framework 泛型类 System.Collections.Generic.List<T> 来创建 Customer 对象的列表集合。

' Define the class for a customer.
Public Class Customer
    Public Property Name As String
    ' Insert code for other members of customer structure.
End Class

' Create a module-level collection that can hold 200 elements.
Public CustomerList As New List(Of Customer)(200)

' Add a specified customer to the collection.
Private Sub AddNewCustomer(ByVal newCust As Customer)
    ' Insert code to perform validity check on newCust.
    CustomerList.Add(newCust)
End Sub

' Display the list of customers in the Debug window.
Private Sub PrintCustomers()
    For Each cust As Customer In CustomerList
        Debug.WriteLine(cust)
    Next cust
End Sub

CustomerFile 集合的声明指定了它只能包含 Customer 类型的元素。 它还提供 200 个元素的初始容量。 过程 AddNewCustomer 检查新元素的有效性,然后将新元素添加到集合中。 过程 PrintCustomers 使用 For Each 循环来遍历集合并显示集合的元素。

相关主题

术语

定义

Visual Basic 中的数组维数

解释数组中的秩和维度。

如何:在 Visual Basic 中初始化数组变量

描述如何用初始值填充数组。

如何:在 Visual Basic 中反转数组的内容

论述如何反转数组各个元素的顺序。

如何:在 Visual Basic 中对数组进行排序

论述如何按字母顺序对数组的各个元素进行排序。

如何:将一个数组赋给另一个数组 (Visual Basic)

论述用于将数组赋给另一个数组变量的规则和步骤。

如何:将一个数组更改为其他数组 (Visual Basic)

论述可进行什么更改,以及如何完成它们。

如何:向过程或属性传递数组 (Visual Basic)

论述如何以参数的形式将数组传递给过程或属性。

如何:从过程或属性中返回数组 (Visual Basic)

论述如何将数组返回给调用了过程或属性的代码。

数组疑难解答 (Visual Basic)

讨论在使用数组时出现的一些常见问题。

请参见

参考

Dim 语句 (Visual Basic)

ReDim 语句 (Visual Basic)

Array