tl; dr - 編譯器沒有提供足夠的返回類型定義信息來確定在編譯時如何分配內存或如何確定偏移量。
爲了理解這些賦值爲什麼不兼容,有助於理解VBA用來表示每個賦值的基礎數據結構。
.Value
Range
的財產返回Variant
。存儲在Variant
中的類型取決於中的單元格數,即Range
。如果有多個單元格,則返回包含Variant
數組的Variant
。請注意,這是必須返回一個Variant
- 否則你需要索引到一個數組中任何時候你想要一個單元格的值。
VBA是一個基於COM的語言,所以當聲明的東西作爲一個Variant
,它被存儲在一個COM VARIANT結構,它由一個VARTYPE的描述所包含的數據以及一個指針到基礎數據的(類型前面有聯合中的星號)或數據本身(聯合中沒有星號的類型)。在內存方面,它看起來像這樣:
所以,當你使用賦值x = Range("A1:C3").Value
,你描述的Variant
陣列的VARTYPE。這很重要,你會在下面看到。
如果Range
只有一個單元格,你還可以得到一個Variant
,但它包含的基本類型 - 不數組。
當你在VBA中聲明一個數組時,它存儲在一個COM SAFEARRAY結構中,該結構描述數組的方式可以讓其他COM客戶端使用該數組。在內存方面,它看起來像這樣(注意,這是一個一個維數組 - 在最後的SAFEARRAYBOUND實際上與元素的CDIM數的數組):
這基本上就是你得到聲明Dim x(1 To 3, 1 To 3) As Integer
(除了最後會有2個SAFEARRAYBOUNDs)。
請注意,這兩種數據類型之間有兩個非常重要的區別。鬆散類型的聲明Dim x As Variant
允許運行時確定數據區中包含的內容。在Range.Value
賦值的情況下,您將獲得一個兼容類型的Variant
數組的VARTYPE(這也是爲什麼Dim x() As Variant
將編譯)。聲明Dim y(1 To 3, 1 To 3) As Integer
是在編譯時固定。更重要的是,由於內存中SAFEARRAY結構的大小由維數決定,因此編譯器可以在編譯時分配內存。但是,由COM調用返回的分配給任意SAFEARRAY結構的內存量不能。此外,指向的內存區域的大小由所包含類型的字節長度和元素總數決定。編譯器通過禁止分配來防止不匹配的可能性。
事實上,這可能是爲什麼你不能直接獲得一個指向SAFEARRAY的原因(這樣做的唯一辦法是轉換爲Variant
手動取消引用指針從它的數據區):
Dim x(1 To 3, 1 To 3) As Integer
Debug.Print VarPtr(x) '<- Type mismatch.
因此,不能這樣做,因爲編譯器沒有足夠的信息來安全地進行運行時轉換。如果你想要做的引擎蓋下一點戳,這個代碼演示了什麼是引擎蓋下發生:
Public Declare Sub CopyMemory Lib "kernel32" Alias _
"RtlMoveMemory" (Destination As Any, Source As Any, _
ByVal length As Long)
Public Type ComVariant
VarType As Integer
Reserved1 As Integer
Reserved2 As Integer
Reserved3 As Integer
DataArea As Long
End Type
Public Sub ExamineVariables()
Dim x As Variant
x = Range("A1:C3").Value
Dim testV As ComVariant
CopyMemory testV, x, LenB(testV)
Debug.Print testV.VarType '= 8204 = 0x200C = VT_ARRAY & VT_VARIANT
Debug.Print testV.DataArea 'Varies - is a SafeArray pointer.
Dim y(1 To 3, 1 To 3) As Integer
View2dArrayType y
End Sub
Public Sub View2dArrayType(vbArray As Variant)
Dim testV As ComVariant
'The VT_BYREF can be ignored - it is an artifact of the cast to Variant.
CopyMemory testV, vbArray, LenB(testV)
Debug.Print testV.VarType '= 24578 = 0x6002 = VT_ARRAY & VT_BYREF & VT_I2
End Sub
你的第一個聲明是Variant
一個數組,其中每個元素都是12個字節長。你的第二個聲明是一個Integer
的數組,每個元素的長度爲2個字節。在編譯時,返回的內存區域的長度和合適的強制轉換都不能可靠地確定。 VBA可以保護您免受訪問衝突和/或運行時錯誤轉換。
爲什麼你希望***能夠分配一個Variant類包含一個2d數組,以便將其分配給一個Integer類型的1d數組? – Comintern
我的不好,x應該被聲明爲一個二維數組,但即使這樣做後,我得到了相同的錯誤 –
爲什麼你希望能夠分配一個Variant'包含一個2d數組可分配給一個** * Integer的2d數組***? – Comintern