VBA не замыкается на короткое замыкание
VBA не поддерживает короткое замыкание - по-видимому, потому, что он имеет только побитовые операции And/Or/Not и т.д. Из спецификации VBA языка: "Логические операторы - это простые операторы данных, которые выполняют побитовые вычисления в своих операндах". В этом свете имеет смысл, что VBA был спроектирован с true = &H1111
и false = &H0000
: таким образом логические операторы могут быть оценены как побитовые операции.
Отсутствие короткого замыкания может вызвать проблемы
-
Производительность:
ReallyExpensiveFunction()
всегда будет выполняться, когда этот оператор будет оцениваться, даже если это не нужно по результату левой стороны условияIf IsNecessary() And ReallyExpensiveFunction() Then '... End If
-
Ошибки: если MyObj is Nothing, этот условный статус приведет к ошибке выполнения, поскольку VBA все равно попытается проверить значение
Property
If Not MyObj Is Nothing And MyObj.Property = 5 Then '... End If
Решение, которое я использовал для реализации поведения с короткими ошибками, является вложенным If
s
If cond1 And cond2 Then
'...
End If
становится
If cond1 Then
If cond2 Then
'...
End If
End If
Таким образом, операторы If дают поведение с коротким замыканием, которое не мешает оценить cond2
, если cond1
- False
.
Если есть предложение Else, это создает повторяющиеся кодовые блоки
If Not MyObj Is Nothing And MyObj.Property = 5 Then
MsgBox "YAY"
Else
MsgBox "BOO"
End If
становится
If Not MyObj Is Nothing Then
If MyObj.Property = 5 Then
MsgBox "YAY"
Else
MsgBox "BOO" 'Duplicate
End If
Else
MsgBox "BOO" 'Duplicate
End If
Есть ли способ переписать выражения If
для сохранения поведения короткого замыкания, но избегать дублирования кода?
Возможно, с другим выражением ветвления типа Select Case
?
Чтобы добавить контекст к вопросу, вот конкретный случай, на который я смотрю. Я реализую хеш-таблицу, которая обрабатывает конфликты, связывая их в связанном списке. Размер базового массива принудительно исполняется в два раза, а хеши распределяются в текущий размер массива, обрезая их до соответствующей длины.
Например, предположим, что длина массива равна 16 (двоичная 10000). Если у меня есть ключ с хэшем до 27 (двоичный код 11011), я могу сохранить его в моем 16-сегментном массиве, сохранив только биты в пределах этого размера массива. Индекс, в котором будет храниться этот элемент, будет (hash value) And (length of array - 1)
, который в этом случае равен (binary 11011) And (1111)
, который равен 1011
, который равен 11. Фактический хэш-код сохраняется вместе с ключом в слоте.
При поиске элемента в хеш-таблице в цепочке необходимо проверить как хэш, так и ключ, чтобы определить, что найден правильный элемент. Однако, если хеш не совпадает, тогда нет причин проверять ключ. Я надеялся получить небольшое количество неосязаемого количества производительности, вложив Ifs в режим короткого замыкания:
While Not e Is Nothing
If keyhash = e.hash Then
If Key = e.Key Then
e.Value = Value
Exit Property
Else
Set e = e.nextEntry
End If
Else
Set e = e.nextEntry
End If
Wend
Вы можете видеть, что Set...
дублируется, и, следовательно, этот вопрос.