Visual Basic 中的陣列

「陣列」(Array) 是一組邏輯相關值,例如文法學校中每一年級的學生數。

陣列讓您可利用相同名稱參考這些相關值,並使用稱為「索引」(Index) 或「註標」(Subscript) 的數字來加以區分。 這些個別值稱為陣列的「元素」(Element)。 它們是從索引 0 到最高索引值的連續值。

相對於陣列,包含單一值的變數稱為「純量」(Scalar) 變數。

範例

下列範例宣告含有文法學校中每一年級學生數目的陣列變數。

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 使用一個索引,也就是「一維」(One-dimensional)。 使用一個以上的索引或註標則稱為「多維」(Multidimensional)。 如需詳細資訊,請參閱 Visual Basic 中的陣列維度

另一種陣列則是存放其他陣列做為自身元素的陣列。 這也就是所謂的「陣列的陣列」(Array of Arrays) 或「不規則陣列」(Jagged Array)。 不規則陣列可以是一維或多維,其元素也一樣。 有時候應用程式中的資料結構會是非矩形的二維陣列。 例如,您可能有一個月份陣列,而該陣列的每個元素則是日期陣列。 由於不同月份的天數也不同,因此這些元素不會形成矩形的二維陣列。 在這種情況下,您可以使用不規則陣列替代多維陣列。

宣告陣列

您可使用 Dim 陳述式 (Statement) 來宣告陣列變數,方式和其他變數相同。 您可以在變數名稱後面加上一組或多組括號,用以表示它是陣列而非「純量」(Scalar) (包含單一值的變數)。

若要宣告一維陣列變數,請在變數名稱之後新增一組括號。

Dim cargoWeights() As Double

若要宣告多維陣列變數,請在變數名稱之後新增一組括號,並在括號內放置逗點以分隔維度。

Dim atmospherePressures(,,,) As Short

若要宣告不規則陣列變數,請在變數名稱之後新增多組括號,組數和巢狀陣列的層數相同。

Dim inquiriesByYearMonthDay()()() As Byte

前述範例只宣告陣列變數,但是未對其指派陣列。 您仍然必須建立陣列,將它初始化,然後將其指派給變數。

長度為零的陣列

沒有元素的陣列也稱為「長度為零的陣列」(Zero-length Array)。 含有長度為零的陣列的變數並不會具有 Nothing 值。 若要建立沒有元素的陣列,請將其中一個陣列的維度宣告為 -1,如下列範例所示。

Dim twoDimensionalStrings(-1, 3) As String

在下列情況中,您可能需要建立長度為零的陣列:

  • 程式碼需要存取 Array 類別的成員 (例如 LengthRank) 或呼叫 Visual Basic 函式 (例如 UBound),而不會有發生 NullReferenceException 例外狀況的風險。

  • 您希望不需檢查 Nothing (以特殊情況處理),讓使用程式碼更簡單。

  • 程式碼會與應用程式發展介面 (Application Programming Interface,API) 互動,這個介面會要求您傳遞長度為零的陣列給一個或多個程序,或從一個或多個程序傳回長度為零的陣列。

建立陣列

建立陣列的方法有兩種。 您可以在宣告陣列時提供陣列的大小,或者,由於陣列是物件,因此可以使用 New 運算子 (Visual Basic) 子句來建立,然後再將其指派給陣列變數。 您可以將它當成陣列宣告的一部分,或在後續的指派陳述式 (Assignment Statement) 中完成此作業,如下列範例所示。

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

依照這些陳述式 (Statement) 執行的結果,陣列的長度為 0。

注意事項注意事項

New 子句必須指定型別名稱,後面接著括號,最後接著大括號 ({})。 括號並不代表呼叫陣列建構函式 (Constructor), 而是表示該物件型別為陣列型別。 您可以在大括號內提供初始化值。 即使您不會在大括號中加入任何值,編譯器 (Compiler) 還是需要大括號。 因此,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)

在陣列填入初始值

您可以使用陣列常值來建立含有一組初始值的陣列。 陣列常值由大括號 ({}) 括住的逗點分隔值清單構成。

當您使用陣列常值來建立陣列時,可以提供陣列型別 (Array Type) 或者使用型別推斷來判別陣列型別。 下列程式碼同時顯示這兩種選項。

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

使用型別推斷時,陣列的型別是由提供當做陣列常值之值清單中的主型別決定。 「主型別」(Dominant Type) 是陣列常值中的所有其他型別所擴展至的唯一型別。 如果無法決定此唯一型別,主型別將成為陣列中所有其他型別可以縮小至的唯一型別。 如果無法決定所有這些型別,則主型別為 Object。 例如,如果提供給陣列常值的值清單含有型別值 Integer、Long 和 Double,則結果陣列的型別是 Double。 Integer 和 Long 都會擴展為 Double 而且僅限為 Double。 因此,Double 是主型別。 如需詳細資訊,請參閱擴展和縮小轉換 (Visual Basic)。 這些推斷規則適用於針對類別成員中定義之陣列 (即區域變數) 進行的型別推斷。 雖然您可以在建立類別層級的變數時使用陣列常值,但無法在該類別層級使用型別推斷。 因此,在類別層級指定的陣列常值,會將提供當做陣列常值之值的型別推斷為 Object。

您可以明確指定使用陣列常值建立之陣列的元素型別。 在這種情況下,陣列常值中的值必須擴展為陣列元素型別。 下列程式碼範例將從整數清單建立型別為 Double 的陣列。

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

巢狀陣列常值

您可以使用巢狀陣列常值來建立多維陣列。 巢狀陣列常值必須具有一個維度與稱為「順位」(Rank) 的維度數目,該維度數目必須和結果陣列一致。 下列程式碼範例將使用陣列常值建立整數的二維陣列。

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}}

如需其他範例,請參閱 HOW TO:在 Visual Basic 中初始化陣列變數

在陣列中儲存值

您可以使用型別為 Integer 的索引來存取陣列中的每一個位置。 您可以使用以括號括住的陣列索引參照每一個陣列位置,儲存和擷取陣列值。 多維陣列的索引以逗號 (,) 分隔。每一維陣列需要一個索引。 下列範例顯示一些將值儲存在陣列中的陳述式 (Statement)。

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

下列範例顯示一些從陣列中取得值的陳述式 (Statement)。

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。

陣列大小

陣列大小為其所有維度 (Dimension) 長度之乘積。 它代表目前包含於陣列中的元素總數。

下列範例宣告一個三維陣列︰

Dim prices(3, 4, 5) As Long

變數 prices 陣列的整體大小為 (3 + 1) x (4 + 1) x (5 + 1) = 120。

您可以使用 Length 屬性來尋找陣列的大小。 您也可以使用 GetLength 方法來尋找多維陣列中每一維的長度。

您可以指派新的陣列物件或者使用 ReDim 陳述式來調整陣列變數的大小。

處理陣列大小時,請注意幾點︰

維度長度

每個維度的索引都以 0 為起點,也就是它的範圍是由 0 到它的上限 (Upper Bound)。 因此,指定維度的長度會比該維度的宣告上限多 1。

長度限制

每個陣列之維度長度都受限於 Integer 資料型別的最大值,也就是 (2 ^ 31) - 1。 然而,陣列之總大小也同時受限於系統可用的記憶體。 若您試圖對總大小超過可用的 RAM 之陣列進行初始化,Common Language Runtime 將擲回 OutOfMemoryException 例外狀況。

大小及元素大小

陣列大小與其元素的資料型別無關。 大小永遠是指元素的總數,而不是它們於儲存體中所佔的位元組。

記憶體消耗量

對陣列在記憶體中的儲存方式做任何假設都是不安全的。 儲存體會因不同資料寬度的平台而有差異,所以相同陣列於 64 位元系統上所佔記憶體將較 32 位元系統來的多。 當您初始化陣列時,隨著系統組態不同,Common Language Runtime (CLR) 會指派儲存體盡可能將元素存放在一起,或是根據實體硬體界限將它們全部加以調整。 同時,陣列需要耗用儲存體以供其控制資訊使用,此消耗量會隨著維度增加而增加。

陣列型別及其他型別

資料型別

每個陣列都具有其資料型別,但此資料型別不同於陣列元素的資料型別。 沒有任何單一的資料型別適用於所有的陣列。 陣列的型別是由陣列的維度數目 (或稱為「順位」(Rank) 以及陣列元素的資料型別決定。 只要兩個陣列變數具有相同順位且其元素具有相同的資料型別,就會視為具有相同的資料型別。 陣列中維度的長度不會影響陣列的資料型別。

每個陣列繼承自 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 會建立新的陣列,並釋出先前的陣列以供處置 (Dispose)。 這將佔用執行時間。 因此,如果您處理的項目數經常變更,或無法預測需要的最大項目數,您可以使用集合來達到較佳的效能。

集合不需要建立新的物件或複製現有項目,調整大小的執行時間也比陣列 (需使用 ReDim) 短。 但如果大小不變或極少變動,使用陣列可能較有效率。 一如往常,效能大多取決於個別應用程式。 所以不妨試著同時使用陣列和集合。

特殊化集合

.NET Framework 也提供多種類別、介面及結構,以供一般及特殊集合使用。 System.CollectionsSystem.Collections.Specialized 命名空間包含定義及實作,其中又包括了字典、清單、佇列及堆疊。 System.Collections.Generic 命名空間提供了許多泛型版本,而這些版本需要一個或多個的型別引數。

如果您的集合只用於存放一種特殊資料型別的項目,使用泛型集合可幫助加強「型別安全」(Type Safety)。 如需泛型的詳細資訊,請參閱 Visual Basic 中的泛型型別 (Visual Basic)

特殊化集合

.NET Framework 也提供多種類別、介面及結構,以供一般及特殊集合使用。 System.CollectionsSystem.Collections.Specialized 命名空間包含定義及實作,其中又包括了字典、清單、佇列及堆疊。 System.Collections.Generic 命名空間提供了許多泛型版本,而這些版本需要一個或多個的型別引數。

如果您的集合只用於存放一種特殊資料型別的項目,使用泛型集合可幫助加強「型別安全」(Type Safety)。 如需泛型的詳細資訊,請參閱 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 中的陣列維度

說明陣列中的陣序規範和維度 (Dimension)。

HOW TO:在 Visual Basic 中初始化陣列變數

描述如何在陣列中填入初始值。

HOW TO:在 Visual Basic 中將陣列內容反向

描述如何反向排列陣列元素。

HOW TO:在 Visual Basic 中排序陣列

示範如何依字母順序排列陣列中的元素。

HOW TO:指派一個陣列至另一個陣列 (Visual Basic)

描述將陣列指派給另一個陣列變數的規則和步驟。

HOW TO:將陣列變更為不同的陣列 (Visual Basic)

討論哪些是可能的變更,以及如何完成這些變更。

HOW TO:傳遞陣列至程序或屬性 (Visual Basic)

說明如何將陣列當做引數傳遞到程序或屬性。

HOW TO:從程序或屬性傳回陣列 (Visual Basic)

描述如何將陣列傳回到會呼叫程序或屬性的程式碼。

疑難排解陣列 (Visual Basic)

討論在使用陣列時會引發的一些常見問題。

請參閱

參考

Dim 陳述式 (Visual Basic)

ReDim 陳述式 (Visual Basic)

Array