Как проверить, не является ли вариантный массив нераспределенным?
Dim Result() As Variant
В окне просмотра это выглядит как
Expression | Value | Type
Result | | Variant/Variant()
Как проверить следующее:
if Result is nothing then
или
if Result is Not Set then
Это в основном то, что я пытаюсь выполнить, но первый не работает, а второй не существует.
Ответы
Ответ 1
Чип Пирсон создал полезный модуль с именем modArraySupport, который содержит набор функций для проверки подобных вещей. В вашем случае вы хотели бы использовать IsArrayAllocated
.
Public Function IsArrayAllocated(Arr As Variant) As Boolean
Эта функция возвращает TRUE или FALSE, указывающие, выделен ли указанный массив (не пустой). Возвращает ИСТИНА массив - это статический массив или динамический объект, который был выделен с помощью оператора Redim. Возвращает FALSE, если массив является динамическим массивом, который еще не был измерен с ReDim или был освобожден с помощью оператора Erase. Эта функция в основном противоположна ArrayIsEmpty. Например,
Dim Result() As Variant
Dim R As Boolean
R = IsArrayAllocated(Result) ' returns false
ReDim V(1 To 10)
R = IsArrayAllocated(Result) ' returns true
Методика, в основном, используется для проверки границ массива (как это было предложено @Tim Williams), НО с дополнительным уловком.
Чтобы проверить в вашем ближайшем окне:
?IsArrayAllocated(Result)
Тестирование в окне Watch: могут быть способы сделать это; например, добавьте часы на R
и в разделе "Тип часов" выберите "Перерыв при изменении значения".
Ответ 2
Чтобы избежать обработки ошибок, я использовал это, увиденное на форуме давным-давно и успешно используя с тех пор:
If (Not Not Result) <> 0 Then 'Means it is allocated
или, альтернативно,
If (Not Not Result) = 0 Then 'Means it is not allocated
Я использовал это главным образом для расширения размера массива из unset массива таким образом
'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
Ответ 3
В ближайшем окне вы можете использовать следующее:
?Result Is Nothing
?IsNull( Result )
?IsEmpty( Result )
?IsMissing( Result )
Первое просто для полноты. Поскольку Result не является объектом, Result Is Nothing
выдаст ошибку. Empty
для вариантов, которые не были инициализированы , включая массивы, которые не были определены..
(Update) При выполнении дополнительной проверки я обнаружил, что IsEmpty никогда не вернет true в объявленном массиве (будь то Redim'd или нет) только с одним исключением. Единственное исключение, которое я нашел, - это когда массив объявлен на уровне модуля, а не как Public, а затем только тогда, когда вы проверяете его в непосредственном окне.
Missing
, если для дополнительных значений передано функции или под. Пока вы не можете объявить Optional Foo() As Variant
, вы можете иметь что-то вроде ParamArray Foo() As Variant
, в этом случае, если ничего не передано, IsMissing
вернет 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
Btw, следует отметить, что эта подпрограмма (или библиотека, выложенная Жаном-Франсуа Корбеттом) вернет false, если массив задан и затем удален.
Ответ 4
Проверьте LBound
массива. Если вы получите сообщение об ошибке, то оно не инициализируется.
Ответ 5
Я рекомендую немного другой подход, потому что я думаю, что использование артефактов языка, таких как (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% векторного хранилища теряется.
Ответ 6
Я думаю, что в строке 4 принятого ответа должно быть сказано:
ReDim Result(1 To 10)
Вместо:
ReDim V(1 To 10)
Я верю в строку 5:
R = IsArrayAllocated(Result) ' returns true
вернет FALSE, как в строке 3:
R = IsArrayAllocated(Result) ' returns false
потому что Result - это не то, что пересмотрено в строке 4.
В строке 4 пытается изменить размерность массива V, но он даже не объявлен.