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为false,但是仍在评估之后的语句。这给了我运行时超出范围错误的下标。
VBA是否真的继续评估And的第二个参数,即使第一个参数是假的?
答案 0 :(得分:54)
答案 1 :(得分:10)
作为DOK mentioned:不,VBA没有短路评估。
使用2 If-then
语句而不是使用AND
运算符在技术上更有效率,但除非你这么做很多次,否则你不会注意到节省,所以不管怎么说更具可读性。如果你想获得真正的技术,VBA也会比If-then
语句更快地处理多个Select Case
语句。
VBA古怪:)
答案 2 :(得分:2)
答案是肯定的,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
答案 3 :(得分:2)
VBA确实有一种短路行为。
通常Null
通过表达式传播,例如。 3 + Null
为Null
,True And Null
为Null
。
但是:
? False And Null
False
这看起来像是短路行为 - 发生了什么?当结点(Null
)的另一个参数为And
或False
时,0
不会传播 - 结果只是False
或{{ 1}}。如果它是左或右参数并不重要。如果析取(0
)的另一个参数是Or
或非零整数(浮点值将使用this rule舍入为整数),则同样适用。
因此,在True
和And
的参数中无法阻止副作用和错误,但Or
传播可能会被短路&#34; 。此行为似乎继承自SQL。
答案 4 :(得分:1)
由于答案是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
解决方案:
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
级联的一行上,并且有相当多的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
答案 5 :(得分:0)
我认为这是最好的做法:
function so_39267627_form_field( $field, $key, $args, $value ){
if ( $args['required'] ) {
$args['class'][] = 'validate-required';
$required = ' <abbr class="required" title="' . esc_attr__( 'required', 'woocommerce' ) . '">*</abbr>';
} else {
$required = '';
}
$args['maxlength'] = ( $args['maxlength'] ) ? 'maxlength="' . absint( $args['maxlength'] ) . '"' : '';
if ( is_string( $args['label_class'] ) ) {
$args['label_class'] = array( $args['label_class'] );
}
if ( is_null( $value ) ) {
$value = $args['default'];
}
// Custom attribute handling
$custom_attributes = array();
// Custom attribute handling
$custom_attributes = array();
if ( ! empty( $args['custom_attributes'] ) && is_array( $args['custom_attributes'] ) ) {
foreach ( $args['custom_attributes'] as $attribute => $attribute_value ) {
$custom_attributes[] = esc_attr( $attribute ) . '="' . esc_attr( $attribute_value ) . '"';
}
}
$field = '';
$label_id = $args['id'];
$field_container = '<p class="form-row %1$s" id="%2$s">%3$s</p>';
$field .= '<input type="' . esc_attr( $args['type'] ) . '" class="input-text ' . esc_attr( implode( ' ', $args['input_class'] ) ) .'" name="' . esc_attr( $key ) . '" id="' . esc_attr( $args['id'] ) . '" placeholder="' . esc_attr( $args['placeholder'] ) . '" ' . $args['maxlength'] . ' ' . $args['autocomplete'] . ' value="' . esc_attr( $value ) . '" ' . implode( ' ', $custom_attributes ) . ' required />';
if ( ! empty( $field ) ) {
$field_html = '';
$field_html .= $field;
if ( $args['description'] ) {
$field_html .= '<span class="description">' . esc_html( $args['description'] ) . '</span>';
}
if ( $args['label'] && 'checkbox' != $args['type'] ) {
$field_html .= '<label for="' . esc_attr( $label_id ) . '" class="' . esc_attr( implode( ' ', $args['label_class'] ) ) .'">' . $args['label'] . $required . '</label>';
}
$container_class = 'form-row ' . esc_attr( implode( ' ', $args['class'] ) );
$container_id = esc_attr( $args['id'] ) . '_field';
$after = ! empty( $args['clear'] ) ? '<div class="clear"></div>' : '';
$field = sprintf( $field_container, $container_class, $container_id, $field_html ) . $after;
}
return $field; }
add_filter( 'woocommerce_form_field_password', 'so_39267627_form_field', 10, 4 );
add_filter( 'woocommerce_form_field_text', 'so_39267627_form_field', 10, 4 );
add_filter( 'woocommerce_form_field_email', 'so_39267627_form_field', 10, 4 );
add_filter( 'woocommerce_form_field_tel', 'so_39267627_form_field', 10, 4 );
add_filter( 'woocommerce_form_field_number', 'so_39267627_form_field', 10, 4 );
因此,当且仅当条件i已满时,您才会通过条件。
答案 6 :(得分:-1)
考虑必须运行的机器代码。 最快的应该是像......的混合代码一样。
如果sfsf然后转到SkipAB
如果fdf然后goto goneBad
如果dffdefedwf然后转到MustHave
SkipAB: 如果dsda&gt; 4然后是MustHave
GoneBad: 退出功能
MustHave: ThisIS = true
&#39;程序必须运行它只会节省一些时间 成千上万次...例如,搜索大型驱动器的文件 或者,当使用简单的布尔测试来跳过耗时的函数时 比如在封闭的工作表中查找所有工作表和名称 [代码]
If Not wFF.UsingFileExtMatch Then GoTo SkipExt
If Not wFF.OKFileEXTMatch Then GoTo BADFile
SkipExt: 如果不是wFF.UsingFileNameMatch那么GoTo SkipFileMatch 如果不是wFF.OKFileNameMatch那么GoTo BADFile SkipFileMatch: 如果不是wFF.UsingDaysAgo那么GoTo SkipDaysAgo 如果不是wFF.OKDaysAgo那么GoTo BADFile SkipDaysAgo:
[/代码]