如何检查变量数组是否未分配?

发布于 2024-10-27 13:13:41 字数 341 浏览 2 评论 0原文

   Dim Result() As Variant

在我的监视窗口中,这显示为

Expression | Value | Type
Result     |       | Variant/Variant()

如何检查以下内容:

   if Result is nothing then

   if Result is Not Set then

这基本上是我想要完成的任务,但第一个不起作用,第二个不存在。

   Dim Result() As Variant

In my watch window, this appears as

Expression | Value | Type
Result     |       | Variant/Variant()

How do I check the following:

   if Result is nothing then

or

   if Result is Not Set then

This is basically what I am trying to accomplish, but the first one does not work and the second does not exist.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

我很坚强 2024-11-03 13:13:41

为了避免错误处理,我使用了这个,很久以前在论坛上看到过,并且从那时起就成功使用了:

If (Not Not Result) <> 0 Then 'Means it is allocated

或者

If (Not Not Result) = 0 Then 'Means it is not allocated

我主要使用它来通过这种方式扩展未设置数组的数组大小

'Declare array
Dim arrIndex() As Variant        

'Extend array
If (Not Not Result) = 0 Then
    ReDim Preserve Result(0 To 0)
Else
    ReDim Preserve Result(0 To UBound(Result) + 1)
End If

To avoid error handling, I used this, seen on a forum long time ago and used sucessfully since then:

If (Not Not Result) <> 0 Then 'Means it is allocated

or alternatively

If (Not Not Result) = 0 Then 'Means it is not allocated

I used this mainly to extend array size from unset array this way

'Declare array
Dim arrIndex() As Variant        

'Extend array
If (Not Not Result) = 0 Then
    ReDim Preserve Result(0 To 0)
Else
    ReDim Preserve Result(0 To UBound(Result) + 1)
End If
帥小哥 2024-11-03 13:13:41

Chip Pearson 制作了一个名为 modArraySupport 的有用模块,其中包含一堆用于测试事物的函数像这样。在您的情况下,您可能需要使用IsArrayAllocation

Public Function IsArrayAllocated(Arr As Variant) As Boolean

该函数返回 TRUE 或 FALSE,指示指定的数组是否已分配(非空)。返回 TRUE
array 是静态数组或已使用 Redim 语句分配的动态数组。如果数组是动态数组,则返回 FALSE
尚未使用 ReDim 调整大小或已使用 Erase 语句取消分配。这个函数基本上是相反的
数组为空。例如,

Dim V() As Variant
Dim R As Boolean
R = IsArrayAllocated(V)  ' returns false
ReDim V(1 To 10)
R = IsArrayAllocated(V)  ' returns true

所使用的技术基本上是测试数组边界(如@Tim Williams 建议的),但有一个额外的陷阱。

要在您的直接窗口中进行测试:

?IsArrayAllocated(Result)

在观察窗口中测试:有多种方法可以做到这一点;例如,在 R 上添加一个监视,并在“监视类型”下选择“值更改时中断”。

Chip Pearson made a useful module called modArraySupport that contains a bunch of functions to test for things like this. In your case, you would want to use IsArrayAllocated.

Public Function IsArrayAllocated(Arr As Variant) As Boolean

This function returns TRUE or FALSE indicating whether the specified array is allocated (not empty). Returns TRUE of the
array is a static array or a dynamic that has been allocated with a Redim statement. Returns FALSE if the array is a dynamic array that
has not yet been sized with ReDim or that has been deallocated with the Erase statement. This function is basically the opposite of
ArrayIsEmpty. For example,

Dim V() As Variant
Dim R As Boolean
R = IsArrayAllocated(V)  ' returns false
ReDim V(1 To 10)
R = IsArrayAllocated(V)  ' returns true

The technique used is basically to test the array bounds (as suggested by @Tim Williams) BUT with an extra gotcha.

To test in your immediate window:

?IsArrayAllocated(Result)

Testing in Watch window: there are may ways to do this; for example, add a watch on R and under "Watch Type" select "Break When Value Changes".

我三岁 2024-11-03 13:13:41

您可以在立即窗口中使用以下内容:

?Result Is Nothing
?IsNull( Result )
?IsEmpty( Result )
?IsMissing( Result )

第一个只是为了完整性。由于 Result 不是对象,因此 Result Is Nothing 将抛出错误。 Empty 用于尚未初始化的变体,包括尚未标注尺寸的数组。

(更新)在进行一些额外的检查时,我发现 IsEmpty 永远不会在声明的数组上返回 true(无论是否 Redim'd),只有一个例外。我发现的唯一例外是当数组在模块级别声明而不是公共时,然后仅当您在立即窗口中检查它时。

如果传递给函数或子函数的可选值缺少。虽然您无法声明 Optional Foo() As Variant,但您可以使用 ParamArray Foo() As Variant 之类的内容,在这种情况下,如果没有传递任何内容,则 IsMissing code> 将返回 true。

因此,确定数组是否已初始化的唯一方法是编写一个程序来检查:

Public Function IsDimensioned(vValue As Variant) As Boolean
    On Error Resume Next
    If Not IsArray(vValue) Then Exit Function
    Dim i As Integer
    i = UBound(Bar)
    IsDimensioned = Err.Number = 0
End Function

顺便说一句,应该注意的是,如果数组已确定尺寸并且该例程(或 Jean-François Corbett 发布的库)将返回 false然后删除。

You can use the following in the immediate window:

?Result Is Nothing
?IsNull( Result )
?IsEmpty( Result )
?IsMissing( Result )

The first is simply for completeness. Since Result is not an object, Result Is Nothing will throw an error. Empty is for variants that have not been initialized including arrays which have not been dimensioned..

(Update) In doing some additional checking, I have discovered that IsEmpty will never return true on a declared array (whether Redim'd or not) with only one exception. The only exception I found is when the array is declared at the module level and not as Public and then only when you check it in the immediate window.

Missing if for optional values passed to a function or sub. While you cannot declare Optional Foo() As Variant, you could have something like ParamArray Foo() As Variant in which case if nothing is passed, IsMissing would return true.

Thus, the only way to determine if the array is initialized is to write a procedure that would check:

Public Function IsDimensioned(vValue As Variant) As Boolean
    On Error Resume Next
    If Not IsArray(vValue) Then Exit Function
    Dim i As Integer
    i = UBound(Bar)
    IsDimensioned = Err.Number = 0
End Function

Btw, it should be noted that this routine (or the library posted by Jean-François Corbett) will return false if the array is dimensioned and then erased.

稚气少女 2024-11-03 13:13:41

检查数组的LBound。如果出现错误,则表明它尚未初始化。

使用内联错误检查的示例:

Dim u As Long
Dim e As Long
On Error Resume Next
u = UBound(arr)
e = Err.Number
On Error GoTo 0
If e = 9 Then
    'Error 9 = subscript out of bounds.
    'The array is empty.
    Stop
Else
    'The array is not empty.
    Stop 
End If

Check the LBound of the array. If you get an error then it's uninitialized.

Example which uses inline error checking:

Dim u As Long
Dim e As Long
On Error Resume Next
u = UBound(arr)
e = Err.Number
On Error GoTo 0
If e = 9 Then
    'Error 9 = subscript out of bounds.
    'The array is empty.
    Stop
Else
    'The array is not empty.
    Stop 
End If
烂柯人 2024-11-03 13:13:41

我建议采用稍微不同的方法,因为我认为使用像 (Not Array) = -1 这样的语言工件来检查初始化很难阅读,并且会导致维护麻烦。

如果您需要检查数组分配,很可能是因为您正在尝试创建自己的“向量”类型:一个在运行时增长以容纳添加数据的数组。如果您利用类型系统,VBA 可以相当容易地实现向量类型。

Type Vector
    VectorData() As Variant
    VectorCount As Long
End Type

Dim MyData As Vector

Sub AddData(NewData As Variant)
    With MyData
        ' If .VectorData hasn't been allocated yet, allocate it with an
        ' initial size of 16 elements.
        If .VectorCount = 0 Then ReDim .VectorData(1 To 16)

        .VectorCount = .VectorCount + 1

        ' If there is not enough storage for the new element, double the
        ' storage of the vector.
        If .VectorCount > UBound(.VectorData) Then
            ReDim Preserve .VectorData(1 To UBound(.VectorData) * 2)
        End If

        .VectorData(.VectorCount) = NewData
    End With
End Sub

' Example of looping through the vector:
For I = 1 To MyData.VectorCount
    ' Process MyData.VectorData(I)
Next

请注意,在此代码中无需检查数组分配,因为我们只需检查 VectorCount 变量即可。如果它是 0,我们就知道向量中还没有添加任何内容,因此数组未分配。

这段代码不仅简单明了,向量还具有数组的所有性能优势,并且添加元素的摊余成本实际上是 O(1),非常高效。唯一的代价是,由于每次向量用完空间时存储空间都会加倍,在最坏的情况下,向量的存储空间有 50% 被浪费。

I recommend a slightly different approach because I think using language artifacts like (Not Array) = -1 to check for initialization is difficult to read and causes maintenance headaches.

If you are needing to check for array allocation, most likely it's because you're trying to make your own "vector" type: an array that grows during runtime to accommodate data as it is being added. VBA makes it fairly easy to implement a vector type, if you take advantage of the type system.

Type Vector
    VectorData() As Variant
    VectorCount As Long
End Type

Dim MyData As Vector

Sub AddData(NewData As Variant)
    With MyData
        ' If .VectorData hasn't been allocated yet, allocate it with an
        ' initial size of 16 elements.
        If .VectorCount = 0 Then ReDim .VectorData(1 To 16)

        .VectorCount = .VectorCount + 1

        ' If there is not enough storage for the new element, double the
        ' storage of the vector.
        If .VectorCount > UBound(.VectorData) Then
            ReDim Preserve .VectorData(1 To UBound(.VectorData) * 2)
        End If

        .VectorData(.VectorCount) = NewData
    End With
End Sub

' Example of looping through the vector:
For I = 1 To MyData.VectorCount
    ' Process MyData.VectorData(I)
Next

Notice how there's no need to check for array allocation in this code, because we can just check the VectorCount variable. If it's 0, we know that nothing has been added to the vector yet and therefore the array is unallocated.

Not only is this code simple and straightforward, vectors also have all the performance advantages of an array, and the amortized cost for adding elements is actually O(1), which is very efficient. The only tradeoff is that, due to how the storage is doubled every time the vector runs out of space, in the worst case 50% of the vector's storage is wasted.

所谓喜欢 2024-11-03 13:13:41

所以我发现 RandomCoders 方法非常好。但请记住,它仅在将变体声明为数组时才有效:

Sub test()
Dim v() As Variant

    Debug.Print (Not Not v) = 0 'returns true

    v = [A1:B5].Value

    Debug.Print (Not Not v) = 0 'returns false

End Sub

但您也可以通过这种方式检查变体:

Sub test2()
Dim v As Variant

    Debug.Print IsEmpty(v) 'returns true

    v = [A1:B5].Value

    Debug.Print IsEmpty(v) 'returns false

End Sub

So I found RandomCoders approach pretty good. But keep in mind that it only works when you declare the variant as an array:

Sub test()
Dim v() As Variant

    Debug.Print (Not Not v) = 0 'returns true

    v = [A1:B5].Value

    Debug.Print (Not Not v) = 0 'returns false

End Sub

But you can also check variants this way:

Sub test2()
Dim v As Variant

    Debug.Print IsEmpty(v) 'returns true

    v = [A1:B5].Value

    Debug.Print IsEmpty(v) 'returns false

End Sub
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文