【问题标题】:What are the rules governing usage of parenthesis in VBA function calls?在 VBA 函数调用中使用括号的规则是什么?
【发布时间】:2023-03-12 16:58:01
【问题描述】:

由于我在传递给我定义的 Sub 的参数周围使用括号而导致 VBA (Access 2003) 中出现“编译器错误”,这令人恼火 30 分钟。

我一直在寻找一篇关于何时需要/适当/不适当/禁止括号的体面文章/教程/说明,但找不到任何明确的指导方针。

【问题讨论】:

标签: ms-access vba syntax


【解决方案1】:

来自Here

使用 VBScript 调用语句调用子程序 当您希望调用子程序时,使用 Call 语句是可选的。与 Sub 一起使用时 Call 语句的目的是允许您将参数列表括在括号中。但是,如果子例程不传递任何参数,那么在使用 Call 语句调用 Sub 时仍然不应该使用括号。

Call MySubroutine

如果子例程有参数,则在使用 Call 语句时必须使用括号。如果有多个参数,则必须用逗号分隔参数。

Call MySubroutine(intUsageFee, intTimeInHours, "DevGuru") 

调用函数 调用函数有两种可能的方式。您可以直接按名称调用该函数,也可以使用 VBScript Call 语句调用它。

按名称调用函数 当直接按名称调用函数并且没有对返回值赋值时,以下所有语法都是合法的:

MyFunction
MyFunction()
MyFunction intUsageFee, intTimeInHours, "DevGuru"

如果需要返回值,可以将函数分配给变量。请注意,如果有一个或多个参数,则必须使用括号。

returnval = MyFunction
returnval = MyFunction()
returnval = MyFunction(intUsageFee, intTimeInHours, "DevGuru") 

【讨论】:

  • 谢谢 - 看起来我的问题是因为我的函数没有返回值,但我仍然在参数列表周围使用括号。这似乎是一个相当奇怪的语法决定......
【解决方案2】:

当你使用 Call MySub你应该在参数周围使用括号,但是如果你省略Call,你就不需要括号了。

【讨论】:

    【解决方案3】:

    我只花了 10 分钟找出一个“类型不兼容”异常,同时调用一个接受 1 个参数的 Sub

    CallMe(argument)
    

    事实证明,这是无效的,谷歌搜索最终将我带到这里

    Call CallMe(argument)
    

    CallMe argument
    

    成功了。因此,在没有只接受 1 个参数的调用语句的情况下调用 sub 时,不能使用方括号。

    【讨论】:

    • +_1 表示子名称
    【解决方案4】:

    我刚刚发现调用带有 / 不带括号的函数的一些奇怪行为。 Google 把我带到了这里。

    sub test()
      dim a as double
      a = 1#
      p(a) 'this won't change a's value
      Debug.Print a '1
      p a  ' this is expected behavior
      Debug.Print a '2
      Call p(a) 'this is also valid
      Debug.Print a '3
    end sub
    
    Function p(a as Double) 'default is byref
      a = a + 1
    end function
    

    我的结论是,当调用只有一个参数的函数时,您必须使用 Call 或省略括号,否则参数不会通过引用传递(它仍然会被调用,正如我已经检查过的那样)。

    【讨论】:

    • 括号确实强制传递参数ByVal
    【解决方案5】:

    VB(A)中的括号规则有完美的逻辑,它是这样的。

    如果使用参数调用过程(函数或子程序),并且调用与其他语句或关键字位于同一行,则参数必须用括号括起来。这是为了将属于过程调用的参数与该行的其余部分区分开来。所以:

    1:   If CheckConditions(A, B, C) = DONT_PROCEED Then Exit Sub
    

    是一个有效的行;对 CheckConditions 的调用需要括号来指示该行的其他哪些位是它的参数。相反,这会产生语法错误:

    2:   If CheckConditions A, B, C = DONT_PROCEED Then Exit Sub
    

    因为无法解析。

    将过程调用作为该行中唯一的语句,不需要括号,因为很明显参数属于过程调用:

    3:   SaveNewValues Value1, Value2, Value3
    

    虽然这会导致语法错误(出于下面讨论的合理原因):

    4:   SaveNewValues(Value1, Value2, Value3)
    

    为了避免混淆括号或没有括号(实际上,要完全避免括号规则),对此类调用使用 Call 关键字总是一个好主意;这确保过程调用不是该行中唯一的语句,因此需要括号:

    5:   Call SaveNewValues(Value1, Value2, Value3)
    

    因此,如果您习惯于在自包含过程调用之前使用 Call 关键字,则可以忘记括号规则,因为您可以始终将参数括在括号中。

    括号在 VB(A)(和许多其他语言)中扮演的额外角色使问题变得混乱:它们还指示表达式的计算优先级。如果您在任何其他上下文中使用括号而不是包含过程调用参数,VB(A) 将尝试将括号中的表达式计算为结果简单值。

    因此,在示例 4 中,括号对于包含参数是非法的,VB(A) 将改为尝试计算括号中的表达式。由于 (Value1, Value 2, Value3) 不是可以计算的表达式,因此会出现语法错误。

    这也解释了为什么如果参数包含在括号中,则使用传递 ByRef 的变量调用就像调用 ByVal 一样。在上面的例子中,函数 p 是用 ByRef 参数 a 调用的,这两个对 p 的调用有很大的不同:

    6:  p a
    

    7:  p(a)
    

    如上所述,6 是正确的语法:调用是单独的,因此不应使用括号括住参数。

    在 7 中,无论如何,参数都包含在括号中,提示 VB(A) 将包含的表达式计算为一个简单值。这当然是传递 ByVal 的定义。括号确保传递 a 的值而不是指向 a 的指针,并且 a 保持不变。

    这也解释了为什么括号规则似乎并不总是占据主导地位。最明显的例子是 MsgBox 调用:

    8:  MsgBox "Hello World!"
    

    还有

    9:  MsgBox ("Hello World!")
    

    都是正确的,即使括号规则规定 9 应该是错误的。当然是这样,但所发生的只是 VB(A) 计算括号中的表达式。并且字符串文字计算为完全相同的字符串文字,因此实际调用是 8。换句话说:使用常量或字符串文字参数调用单参数过程具有相同的结果,带或不带括号。 (这就是为什么我的 MsgBox 调用前面都带有 Call 关键字的原因。)

    最后,这解释了在传递 Object 参数时奇怪的类型不匹配错误和奇怪的行为。假设您的应用程序有一个 HighlightContent 过程,该过程将 TextBox 作为参数(而且,您永远猜不到,它会突出显示它的内容)。你调用它来选择文本框中的所有文本。您可以通过三种语法正确的方式调用此过程:

    10: HighlightContent txtName
    11: HighlightContent (txtName)
    12: Call HighlightContent(txtName)
    

    假设您的用户在文本框中输入了“John”并且您的应用程序调用了 HighlightContent。会发生什么,哪个调用会起作用?

    10 和 12 是正确的;名称 John 将在文本框中突出显示。但是 11 在语法上是正确的,但会导致编译或运行时错误。为什么?因为括号不合适。这将提示 VB(A) 尝试评估括号中的表达式。一个对象的评估结果通常是其默认属性的值; .Text,在这种情况下。所以像11这样调用过程不会将TextBox对象传递给过程,而是一个字符串值“John”。导致类型不匹配。

    【讨论】:

    • +1 是一个很好的答案,但我仍然不同意括号规则是“完全合乎逻辑的”......我无法想象一种更笨拙的方式来处理像括号这样简单的事情!
    • 如果有“点”怎么办? (请随时更正我的术语)myCollection.add objmyCollection.item(obj) 这不是正确的方法吗?但是括号规则不一样,不知道为什么。
    • 对我困惑了一段时间的事情的彻底回答。看起来还是有点傻。其他语言在解析带括号且没有“call”关键字的函数调用时没有任何问题。但是现在我知道了规则,我不会浪费时间试图弄清楚 WTFITMWTSL!,感谢您的帮助。 B^J
    • Call Debug.Print("Hello world") 仍然会引发错误。这背后的逻辑在哪里?
    • @Microsoft,帮自己一个忙,将您的vba/language/concepts/getting-started/using-parentheses-in-code 重定向到这里。
    【解决方案6】:

    1 - 默认情况下,调用过程或函数时不要使用括号:

    MsgBox "Hello World"
    

    2 - 如果你正在调用一个函数,并且对它的结果感兴趣,那么你必须用括号括起来它的参数:

    Dim s As String
    Dim l As Long 
    s = "Hello World"
    l = Len(s)
    

    3 - 如果你想在过程中使用 call 关键字,那么你必须用括号括起来参数(例如,当你想将结果分配给变量或在表达式中使用函数时):

    Call MsgBox("Hello World")
    

    4 - 如果您想强制通过 ByVal 传递 ByRef 参数(默认值),则将 ByRef 参数用括号括起来:

    Sub Test
      Dim text As String
      text = "Hello World"
    
      ChangeArgument((text))
    
      MsgBox text
    End Sub
    
    Sub ChangeArgument(ByRef s As String)
        s = "Changed"
    End Sub
    

    这会显示“Hello World”

    【讨论】:

      【解决方案7】:

      我使用另一种逻辑来区分何时使用括号。如果您的函数不返回值(C 语言中的 void 类型),则不需要括号。对于 subs 来说总是如此,因为返回值是 sub 和 function 之间的主要区别。否则你必须使用括号。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-04-15
        • 2010-11-13
        • 1970-01-01
        • 1970-01-01
        • 2022-04-18
        相关资源
        最近更新 更多