Подтвердить что ты не робот

Оператор VBA "И" оценивает второй аргумент, когда первый является ложным?

Function Foo(thiscell As Range) As Boolean
  Foo = thiscell.hasFormula And (InStr(1, UCase(Split(thiscell.formula, Chr(40))(0)), "bar") > 0)
End Function

Эта функция существует для проверки наличия определенной подстроки (bar в этом случае) до (.

Случай, с которым у меня возникают проблемы, - это когда ячейка, переданная в функцию, пуста, thisCell.hasFormula является ложной, но оператор после и все еще оценивается. Это дает мне индекс ошибок вне диапазона во время выполнения.

Действительно ли VBA продолжает оценивать второй аргумент для И, даже если первый был ложным?

4b9b3361

Ответ 1

То, что вы ищете, называется " оценка короткого замыкания".

У VBA этого нет.

Вы можете увидеть подход, который, вероятно, адаптируется к вашей ситуации здесь.

Подход, выбранный там, заключался в замене a Select Case на If. Существует также пример использования вложенных Ifs.

Ответ 2

Как DOK, упомянутый: Нет, VBA не имеет оценки короткого замыкания.

Технически более эффективно использовать операторы 2 If-then вместо использования оператора AND, но если вы этого не делаете много раз, вы не заметите сбережений, поэтому идите на то, что более читаемо. И если вы хотите получить действительно технический, VBA обрабатывает несколько операторов If-then быстрее, чем Select Case.

VBA причудлива:)

Ответ 3

Ответ: да, VBA не проводит оценку короткого замыкания.

Это не просто вопрос стиля; это имеет большое значение в такой ситуации:

If i <= UBound(Arr, 1) And j <= UBound(Arr, 2) And Arr(i, 1) <= UBound(Arr2, 1) Then
    Arr2(Arr(i, 1), j) = Arr(i, j)
End If

... что неверно. Более целесообразно:

If i <= UBound(Arr, 1) And j <= UBound(Arr, 2) Then
    If Arr(i, 1) <= UBound(Arr2, 1) Then
        Arr2(Arr(i, 1), j) = Arr(i, j)
    End If
End If

Или, если у вас есть отвращение к вложенным ifs:

If i > UBound(Arr, 1) Or j > UBound(Arr, 2) Then
    ' Do Nothing
ElseIf Arr(i, 1) > UBound(Arr2, 1) Then
    ' Do Nothing
Else
    Arr2(Arr(i, 1), j) = Arr(i, j)
End If

Ответ 4

У VBA есть одно поведение, подобное короткому замыканию. Обычно Null распространяется через выражения, например. 3 + Null - Null, а True And Null - Null. Однако:

? False And Null
False

Это похоже на поведение короткого замыкания - что происходит? Null не распространяется, когда другой аргумент конъюнкции (And) равен False или 0 - результат равен всего False или 0. Неважно, если это левый или правый аргумент. То же самое относится, если другим аргументом для дизъюнкции (Or) является True или ненулевое целое число (значение с плавающей запятой округляется до целого с помощью это правило).

Таким образом, побочные эффекты и ошибки не могут быть предотвращены в аргументах And и Or, но Null распространение может быть "закорочено". Это поведение кажется унаследованным от SQL.

Ответ 5

Я думаю, что это лучшая практика:

sub my conditions()
        If Condition1=constraint1 then
         if Condition2=constraint2 then
          if condition3=constraint3 then
           ...
            ....
        end if
         end if
          end if
    else
      end if
           ....
    end if
end sub

Таким образом, вы будете проходить только через условия тогда и только тогда, когда условие я заполнено.

Ответ 6

Так как ответ - один из лучших в Google, который ищет что-то вроде vba if condition not lazy, я хотел бы привести более простой пример, проблему и решения обоих условий: AND и более интересный OR...

Dim cond1 As Boolean   'some 1st condition that may be True or False
Dim obj As Collection  'just some sample object that may or may not be instantiated

(²: мне лучше объяснить другим разработчикам, почему вы не выбрали OR, если они не знают фона)


дело AND

cond1 = False
If cond1 Then Set obj = New Collection

проблема:

If cond1 And obj.Count > 0 Then Debug.Print "Count > 0!"  'throws error if < cond1 = False > 
                                                          'because condition 2 is always evaluated

solution решение:

If cond1 Then If obj.Count > 0 Then Debug.Print "Count > 0!"  'AND would not short-cicuit!² https://stackoverflow.com/a/57521572/1915920

В зависимости от вкуса, сложности и читабельности может иметь смысл написать это так:

If cond1 Then
    If obj.Count > 0 Then  'AND would not short-cicuit!² https://stackoverflow.com/a/57521572/1915920
        Debug.Print "Count > 0!"
    End If
End If

чехол OR

 cond1 = True
 If Not cond1 Then Set obj = New Collection  'obj stays < Nothing > otherwise

проблема:

 If cond1 Or obj.Count = 0 Then Debug.Print "no objects!"  'throws error if < cond1 = True >
                                                           'because condition 2 is always evaluated

решение 1:

на месте, без резервирования, один вкладыш без GoTo с использованием Select:

 Select Case True:  Case cond1, obj.Count = 0:  Debug.Print "no objects!":  End Select  'OR would not short-cicuit!² https://stackoverflow.com/a/57521572/1915920

в случае, если он должен/должен быть на нескольких строках и с некоторыми другими:

 Select Case True
     Case cond1, obj.Count = 0  'OR would not short-cicuit!² https://stackoverflow.com/a/57521572/1915920
         Debug.Print "no objects!"
     Case Else
         Debug.Print "object count: " & obj.Count
 End Select

решение 2:

на месте, не избыточный код с минимальным использованием GoTo, но более длинный If многострочный код:

 If cond1 Then
 noObjs:
     Debug.Print "no objects!"
 ElseIf obj.Count = 0 Then  'OR would not short-cicuit!² https://stackoverflow.com/a/57521572/1915920
     GoTo noObjs
 End If

решение 3:

на месте, условия (могут подходить) в одной строке аналогично OR -concatenation с довольно частым использованием GoTo:

 If cond1 Then GoTo noObjs ElseIf obj.Count = 0 Then GoTo noObjs  'OR would not short-cicuit!² https://stackoverflow.com/a/57521572/1915920
 GoTo skipOnAllFalse
 noObjs:
     Debug.Print "no objects!"

 skipOnAllFalse:    'use more specific label/scenario name if possible

решение 4:

код не на месте (Sub), избегая GoTo, условия (могут подходить) в одной строке, но код модуля/класса может быть более нечитаемым/распространяемым/загроможденным:

 Private Sub noObjs():  Debug.Print "no objects!"

 If cond1 Then noObjs ElseIf obj.Count = 0 Then noObjs  'OR would not short-cicuit!² https://stackoverflow.com/a/57521572/1915920

решение 5:

используя одну переменную условия:

 Dim any As Boolean:  any = cond1
 If Not any Then any = obj.Count = 0  'OR would not short-cicuit!² https://stackoverflow.com/a/57521572/1915920
 If any Then Debug.Print "no objects!"

решение 6:

используя несколько переменных условия:

 Dim c1 As Boolean:  Dim c2 As Boolean
 c1 = cond1
 If Not c1 Then c2 = obj.Count = 0  'OR would not short-cicuit!² https://stackoverflow.com/a/57521572/1915920
 If c1 Or c2 Then Debug.Print "no objects!"  'safe to use Or now

Ответ 7

Рассмотрим машинный код, который должен быть запущен. Самый быстрый должен быть по линии сочетания кода вроде...

если sfsf, а затем перейти SkipAB

если fdf затем перешел в

если dffdefedwf, а затем goto MustHave

SkipAB:  если dsda > 4, то MustHave

GoneBad: функция выхода

Musthave: ThisIS = true

'сохраняет только несколько моментов, когда программа должна запускать его много тысяч раз... например, поиск файлов на большом диске или когда простой булевский тест используется, чтобы пропустить функцию времени как найти все листы и имена в закрытом листе [Код]

     If Not wFF.UsingFileExtMatch Then GoTo SkipExt
                If Not wFF.OKFileEXTMatch Then GoTo BADFile

SkipExt:                   Если не wFF.UsingFileNameMatch, то GoTo SkipFileMatch                   Если не wFF.OKFileNameMatch Then GoTo BADFile SkipFileMatch:                   Если не wFF.UsingDaysAgo, то GoTo SkipDaysAgo                   Если не wFF.OKDaysAgo, то GoTo BADFile SkipDaysAgo:

[/код]