gpt4 book ai didi

arrays - 将多个单元格范围值分配给变量

转载 作者:行者123 更新时间:2023-12-03 01:54:17 25 4
gpt4 key购买 nike

我对以下陈述感到困惑

Dim x as variant
x=Range("A1:C3").value

使用上述语句后,我们可以将 x 用作二维数组,但如果我们将 x 声明为如下所示的数组
Dim x(1 to 3,1 to 3) as integer
x=Range("A1:C3").value

然后使用上面的 statemnet 给我编译时错误说明 Can't assign to an array .

我的疑问是当 x 被声明为变体时代码如何运行良好,但当它被声明为数组时给我错误。

最佳答案

tl;博士 - 返回类型定义没有为编译器提供足够的信息来确定如何分配内存或如何确定在编译时进行转换的偏移量。

为了理解为什么这些分配不兼容,它有助于理解 VBA 用来表示它们中的每一个的底层数据结构。
.Value Range 的属性(property)返回 Variant . Variant 中存储的类型由 Range 中的单元格数决定.如果有多个单元格,则返回 Variant包含 Variant 的数组.注意是 必须返回 Variant - 否则,您需要在任何时候想要从单个单元格中获取值时对数组进行索引。

VBA 是一种基于 COM 的语言,因此当您将某些内容声明为 Variant , 它存储在 COM VARIANTVARTYPE 组成的结构描述包含的数据和指向基础数据的指针(联合中以星号开头的类型)或数据本身(联合中不以星号开头的类型)。在内存中,它看起来像这样:

Variant in memory

所以,当你使用赋值 x = Range("A1:C3").Value ,你会得到一个描述 Variant 数组的 VARTYPE .这很重要,如下所示。

如果 Range只有一个单元格,您还可以获得 Variant , 但它包含基础类型 - 不是 数组。

在 VBA 中声明数组时,它存储在 COM SAFEARRAY 中。结构,以某种方式描述数组,使其可供其他 COM 客户端使用。在内存中它看起来像这样(注意这是一个一维数组 - 最后的 SAFEARRAYBOUND 实际上是一个包含 cDim 中元素数量的数组):

SafeArray in memory

这基本上就是你通过声明 Dim x(1 To 3, 1 To 3) As Integer 得到的。 (除了最后会有 2 个 SAFEARRAYBOUNDs)。

请注意,这两种数据类型之间有 2 个非常重要的区别。松散类型声明 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 保护您免受访问冲突和/或运行时错误强制转换。

关于arrays - 将多个单元格范围值分配给变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38685599/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com