gpt4 book ai didi

VBA 短路 `And` 替代方案

转载 作者:行者123 更新时间:2023-12-03 14:11:01 26 4
gpt4 key购买 nike

这个问题在这里已经有了答案:





AndAlso/OrElse in VBA

(8 个回答)


7年前关闭。




VBA 不会短路

VBA 不支持短路 - 显然是因为它只有按位 And/Or/Not 等操作。来自 VBA language specification :“逻辑运算符是对操作数执行按位计算的简单数据运算符。”从这个角度来看,VBA 是用 true = &H1111 设计的。和 false = &H0000 :这种方式逻辑语句可以被评估为按位运算。

缺少短路会导致问题

  • 性能:ReallyExpensiveFunction()将始终在评估此语句时运行,即使条件左侧的结果不需要它
    If IsNecessary() And ReallyExpensiveFunction() Then
    '...
    End If
  • 错误:如果 MyObj 为 Nothing,此条件语句将导致运行时错误,因为 VBA 仍将尝试检查 Property 的值
    If Not MyObj Is Nothing And MyObj.Property = 5 Then
    '...
    End If

  • 我用来实现短路行为的解决方案是嵌套的 If小号
    If cond1 And cond2 Then
    '...
    End If

    变成
    If cond1 Then
    If cond2 Then
    '...
    End If
    End If

    这样,If 语句给出了类似短路的行为,即无需费心评估 cond2。如果 cond1False .

    如果存在 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 ?

    要为问题添加上下文,这是我正在查看的特定案例。我正在实现一个哈希表,通过将它们链接在一个链表中来处理冲突。底层数组大小被强制为 2 的幂,并且通过将散列截断为适当的长度,散列被分配到当前数组大小中。

    例如,假设数组长度为 16(二进制 10000)。如果我有一个散列为 27(二进制 11011)的 key ,我可以通过仅将位保持在该数组大小的限制内,将其存储在我的 16 槽数组中。存储此项的索引是 (hash value) And (length of array - 1)在这种情况下是 (binary 11011) And (1111)这是 1011即 11。实际的哈希码与 key 一起存储在插槽中。

    在链中查找散列表中的项目时,必须检查散列和键以确定已找到正确的项目。但是,如果散列不匹配,则没有理由检查 key 。我希望通过嵌套 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...是重复的,因此这个问题。

    最佳答案

    作为更通用的方法,我建议引入条件标志并使用将比较结果分配给 bool 值:

    dim cond1 as boolean
    dim cond2 as boolean

    cond1 = false
    cond2 = false

    ' Step 1
    cond1 = MyObj Is Nothing

    ' Step 2: do it only if step 1 was sucessful
    if cond1 then
    cond2 = MyObj.Property = 5
    end if

    ' Final result:
    if cond2 then
    msgbox "Yay"
    else
    msgbox "Boo"
    end if
    通过“链接”这些条件标志,每一步都是安全的,您可以在最后一个条件标志中看到最终结果,并且您不会进行不必要的比较。而且,对我来说,它保持可读性。
    编辑 2014-07-09
    我通常从不省略 block 分隔符,因此我将控制结构的每个语句都设置在新行上。但是在这种情况下,您可以仔细地获得一个非常密集的符号来提醒短路符号,这也是因为 VBA 编译器启动了变量:
    dim cond1 as boolean
    dim cond2 as boolean
    dim cond3 as boolean
    dim cond4 as boolean

    cond1 = MyObj Is Nothing
    if cond1 then cond2 = MyObj.Property = 5
    if cond2 then cond3 = MyObj.Property2 = constSomething
    if cond3 then cond4 = not isNull(MyObj.Property77)

    if cond4 then
    msgbox "Hyper-Yay"
    else
    msgbox "Boo"
    end if
    我可以同意这一点。这是一个清晰的阅读流程。
    编辑 2021-03-21
    感谢@Tom 的评论,可以写得更简单:
    dim cond as boolean

    cond = MyObj Is Nothing
    if cond then cond = MyObj.Property = 5
    if cond then cond = MyObj.Property2 = constSomething
    if cond then cond = not isNull(MyObj.Property77)

    if cond then
    msgbox "Hyper-Yay"
    else
    msgbox "Boo"
    end if
    @Tom 在下面的评论中解释了这些优势。我完全同意这一点。我只能在调试时想象一些情况,当我想分离条件的结果时,因此明确地使用四个不同的变量。

    关于VBA 短路 `And` 替代方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24641923/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com